SurfaceFlinger研究报告
SurfaceFlinger研究报告 1
一.综述与SurfaceFlinger的类结构 2
二.SurfaceFlinger进程 3
1.进程的启动 3
2.SurfaceFlinger主线程的启动 4
3.SurfaceFlinger主线程的初始化 4
4.SurfaceFlinger主线程的运行 4
三.DisplayHardware类 6
1.DisplayHardware的创建 6
2.DisplayEventThread 7
3.DisplayHardware的初始化 9
FramebufferNativeWindow 14
fb_device_open 15
mapFrameBufferLocked 17
gralloc_alloc_framebuffer_locked 20
DisplayHardware::init 22
4.DisplayHardware::flip 22
四.handlePageFlip函数 24
1.State 25
2.lockPageFlip 25
<1>mQueuedFrames 28
<2>more frames 29
<3>SurfaceTexture::updateTexImage 29
3.unlockPageFlip 32
4.handleRepaint 32
<1>setupHardwareComposer 32
<2>composeSurfaces 33
5.postFramebuffer 34
6.handleTransaction 35
一.综述与SurfaceFlinger 的类结构

总体来说,
SurfaceFlinger的作用是为客户进程上的
view提供绘画内存,并把这些
View经过compose
之后,显示在屏幕上。上图显示了在
SurfaceFlinger进程中使用到的各种类及其关系。我们从
ISurface说起,来详细介绍这个类图中的各个类。
SurfaceFlinger进程在收到客户进程创建
ISurface的请求后,首先是根据需求创建
LayerBaseClient,然后由这个LayerBaseClient创建
ISurface,当然各种不同的LayerBaseClient创建的
ISurface也是不同的,ISurface的功能就是获取
ISurfaceTexture,客户进程通过这个接口与
SurfaceFlinger进程上的服务端通信,进行
lock,unlock
之类的操作。而只有
Layer类返回的ISurface
接口才能返回有内容的
ISurfaceTexture实例,其他的ISurface返回的内容都是空的。
Layer类的ISurface
接口实际上是返回的
Layer类中的成员变量mSurfaceTexture,它是一个
SurfaceTextureLayer实例,它继承自SurfaceTexture类。
SurfaceTexture类是一个非常重要的类,基本上它包括两个密不可分的部分,一个是作为服务端实现了
ISurfaceTexture接口,与客户端通信,它包含有
32个GraphicBuffer
,当然他们都是在需要的时候才分配内存,客户端所进行的操作都是针对这个内存的,
SurfaceTexture中有对这些内存的同步和管理功能;另外一个功能就是根据客户端的画好的内存生成
OpenGL|ES image,这个image
最终是要交给
SurfaceFlinger的Composer
混合的,SurfaceTexture的内存实际上就是一个读写队列,客户端会不断要求添加新的帧,SurfaceFlinger的主线程中会去读取这个帧。有了要显示的内容,剩下的工作就是要把它显示到屏幕上了。
SurfaceFlniger中所有和显示相关的动作都封装在
Displayhardware类中,这个类的实例指针是保存在
GraphicPlane实例中,它是SurfaceFlinger的一个成员变量,它代表了一块屏幕,目前只有一个,实际上
SurfaceFlinger可以支持多块屏幕。Displayhardware中包含一个
FramebufferNativeWindow实例指针,它才是真正打开加载硬件设备的类,它继承自
ANativeWindow类,它打开了两个设备,一个是
framebuffer,一个是gralloc
,framebuffer用于写屏幕,
gralloc用于从framebuffer
中分配内存,实际上
FramebufferNativeWindow中的有两个NativeBuffer
,即所谓的
front buffer与back
buffer
,它们的内存就是从
framebuffer中分配的。至此,我们对
SurfaceFlinger中各个类有了大概的了解,下面详细说明
SurfaceFlinger是如何把客户进程的UI显示到屏幕上的。
二.SurfaceFlinger进程
1.进程的启动
在init.rc中,启动了
surfaceflinger服务,
service surfaceflinger /system/bin/surfaceflinger
这个可执行文件是在 frameworks/base/cmds/surfaceflinger/main_surfaceflinger.cpp 编译出来的,该文件的内容非常简单,如下所示:
int main(int argc, char** argv) {
SurfaceFlinger::publishAndJoinThreadPool();
return 0;
}
我们来看 SurfaceFlinger类的定义
frameworks/base/services/surfaceflinger/SurfaceFlinger.h
class SurfaceFlinger :
public BinderService<SurfaceFlinger>,
public BnSurfaceComposer,
public IBinder::DeathRecipient,
protected Thread
在它的基类 BinderService类中,定义了publishAndJoinThreadPool函数,它是一个模板类,该函数定义如下:
static void publishAndJoinThreadPool() {
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
这与我们在前面分析 Binder的时候,添加服务的过程是相同的,同时,我们看到 SurfaceFlinger类也从是BnSurfaceComposer 继承的, BnSurfaceComposer是在frameworks/base/include/surfaceflinger/ISurfaceComposer.h 定义的,它从 BnInterface<ISurfaceComposer>继承而来,也就是说SurfaceFlinger是 ISurfaceComposer接口的服务器端类
service surfaceflinger /system/bin/surfaceflinger
这个可执行文件是在 frameworks/base/cmds/surfaceflinger/main_surfaceflinger.cpp 编译出来的,该文件的内容非常简单,如下所示:
int main(int argc, char** argv) {
SurfaceFlinger::publishAndJoinThreadPool();
return 0;
}
我们来看 SurfaceFlinger类的定义
frameworks/base/services/surfaceflinger/SurfaceFlinger.h
class SurfaceFlinger :
public BinderService<SurfaceFlinger>,
public BnSurfaceComposer,
public IBinder::DeathRecipient,
protected Thread
在它的基类 BinderService类中,定义了publishAndJoinThreadPool函数,它是一个模板类,该函数定义如下:
static void publishAndJoinThreadPool() {
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
这与我们在前面分析 Binder的时候,添加服务的过程是相同的,同时,我们看到 SurfaceFlinger类也从是BnSurfaceComposer 继承的, BnSurfaceComposer是在frameworks/base/include/surfaceflinger/ISurfaceComposer.h 定义的,它从 BnInterface<ISurfaceComposer>继承而来,也就是说SurfaceFlinger是 ISurfaceComposer接口的服务器端类
2.SurfaceFlinger主线程的启动
从前面创建
SurfaceFlinger服务的时候,我们知道SufaceFlinger的类继承结构,
SurfaceFlinger继承自Thread
,看下面的代码
void SurfaceFlinger::onFirstRef()
{
run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
// Wait for the main thread to be done with its initialization
mReadyToRunBarrier.wait();
}
我们从这里可以看到,它调用了 Thread.run函数,该函数会启动一个新的线程, readToRun是该线程的初始化函数,在线程中将运行 threadLoop函数,mReadyToRunBarrier.wait(); 是为了等待线程启动起来,也就是说,在 init进程启动 SurfaceFlinger服务进程之后,创建 SurfaceFlinger实例,并在该实例第一次得到引用的时候,会启动一个新的线程,这个线程就是 调用的就是SurfaceFlinger.threadLoop 函数。
void SurfaceFlinger::onFirstRef()
{
run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
// Wait for the main thread to be done with its initialization
mReadyToRunBarrier.wait();
}
我们从这里可以看到,它调用了 Thread.run函数,该函数会启动一个新的线程, readToRun是该线程的初始化函数,在线程中将运行 threadLoop函数,mReadyToRunBarrier.wait(); 是为了等待线程启动起来,也就是说,在 init进程启动 SurfaceFlinger服务进程之后,创建 SurfaceFlinger实例,并在该实例第一次得到引用的时候,会启动一个新的线程,这个线程就是 调用的就是SurfaceFlinger.threadLoop 函数。
3.SurfaceFlinger主线程的初始化
SurfaceFlinger::readToRun
函数主要用于线程的初始化,其中最关键的是调用了
DisplayHardware::makeCurrent,该函数把当前线程与OpenGL|ES的
Context绑定起来,后面的绘画都是在这个
context中进行的。
4.SurfaceFlinger主线程的运行
bool SurfaceFlinger::threadLoop()
{
waitForEvent();
// check for transactions
if (UNLIKELY(mConsoleSignals)) {
handleConsoleEvents();
}
// if we're in a global transaction, don't do anything.
const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
uint32_t transactionFlags = peekTransactionFlags(mask);
if (UNLIKELY(transactionFlags)) {
handleTransaction(transactionFlags);
}
// post surfaces (if needed)
handlePageFlip();
if (mDirtyRegion.isEmpty()) {
// nothing new to do.
return true;
}
if (UNLIKELY(mHwWorkListDirty)) {
// build the h/w work list
handleWorkList();
}
const DisplayHardware& hw(graphicPlane(0).displayHardware());
if (LIKELY(hw.canDraw())) {
// repaint the framebuffer (if needed)
const int index = hw.getCurrentBufferIndex();
GraphicLog& logger(GraphicLog::getInstance());
logger.log(GraphicLog::SF_REPAINT, index);
handleRepaint();
// inform the h/w that we're done compositing
logger.log(GraphicLog::SF_COMPOSITION_COMPLETE, index);
hw.compositionComplete();
logger.log(GraphicLog::SF_SWAP_BUFFERS, index);
postFramebuffer();
logger.log(GraphicLog::SF_REPAINT_DONE, index);
} else {
// pretend we did the post
hw.compositionComplete();
usleep(16667); // 60 fps period
}
return true;
}
waitForEvent函数在 Surface研究报告中已经有详细说明;下面将分别对 handleConsoleEvent,handleTransaction ,handlePageFlip, handleRepaint,postFrameBuffer 等进行说明
{
waitForEvent();
// check for transactions
if (UNLIKELY(mConsoleSignals)) {
handleConsoleEvents();
}
// if we're in a global transaction, don't do anything.
const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
uint32_t transactionFlags = peekTransactionFlags(mask);
if (UNLIKELY(transactionFlags)) {
handleTransaction(transactionFlags);
}
// post surfaces (if needed)
handlePageFlip();
if (mDirtyRegion.isEmpty()) {
// nothing new to do.
return true;
}
if (UNLIKELY(mHwWorkListDirty)) {
// build the h/w work list
handleWorkList();
}
const DisplayHardware& hw(graphicPlane(0).displayHardware());
if (LIKELY(hw.canDraw())) {
// repaint the framebuffer (if needed)
const int index = hw.getCurrentBufferIndex();
GraphicLog& logger(GraphicLog::getInstance());
logger.log(GraphicLog::SF_REPAINT, index);
handleRepaint();
// inform the h/w that we're done compositing
logger.log(GraphicLog::SF_COMPOSITION_COMPLETE, index);
hw.compositionComplete();
logger.log(GraphicLog::SF_SWAP_BUFFERS, index);
postFramebuffer();
logger.log(GraphicLog::SF_REPAINT_DONE, index);
} else {
// pretend we did the post
hw.compositionComplete();
usleep(16667); // 60 fps period
}
return true;
}
waitForEvent函数在 Surface研究报告中已经有详细说明;下面将分别对 handleConsoleEvent,handleTransaction ,handlePageFlip, handleRepaint,postFrameBuffer 等进行说明
三.DisplayHardware类
SurfaceFlinger所有重要的工作都在threadLoop函数中进行。在分析
threadLoop函数中的其他函数之前,我们需要先分析
DisplayHardware类。
1.DisplayHardware的创建
而在
SurfaceFlinger::readyToRun中,new
DisplayHardware,
并设置给
GraphicPlane。
virtual void onFirstRef() {
run("DisplayEventThread", PRIORITY_URGENT_DISPLAY);
}
status_t SurfaceFlinger::readyToRun()
{
LOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
// 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);
}
。。。。。。
}
virtual void onFirstRef() {
run("DisplayEventThread", PRIORITY_URGENT_DISPLAY);
}
status_t SurfaceFlinger::readyToRun()
{
LOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
// 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);
}
。。。。。。
}
2.DisplayEventThread
DisplayHardware派生自DisplayHardwareBase
,其类图如下:

DisplayHardware在构造函数中new了一个
DisplayEventThreadBase,DisplayEventThreadBase
类在onFirstRef的时候会启动自己
run("DisplayEventThread",PRIORITY_URGENT_DISPLAY);
bool DisplayHardwareBase::DisplayEventThread::threadLoop()
{
int err = 0;
char buf;
int fd;
fd = open(kSleepFileName, O_RDONLY, 0);
do {
err = read(fd, &buf, 1);
} while (err < 0 && errno == EINTR);
close(fd);
LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
if (err >= 0) {
sp<SurfaceFlinger> flinger = mFlinger.promote();
LOGD("About to give-up screen, flinger = %p", flinger.get());
if (flinger != 0) {
mBarrier.close();
flinger->screenReleased(0);
----->android_atomic_or(eConsoleReleased, &mConsoleSignals);
----->mEventQueue.invalidate();
----->mCondition.signal();// 这会使得 MessageQueue::waitMessage函数退出等待
mBarrier.wait();//等待
}
}
fd = open(kWakeFileName, O_RDONLY, 0);
do {
err = read(fd, &buf, 1);
} while (err < 0 && errno == EINTR);
close(fd);
LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
if (err >= 0) {
sp<SurfaceFlinger> flinger = mFlinger.promote();
LOGD("Screen about to return, flinger = %p", flinger.get());
if (flinger != 0)
flinger->screenAcquired(0);
----->android_atomic_or(eConsoleAcquired, &mConsoleSignals);
----->mEventQueue.invalidate();
----->mCondition.signal();// 这会使得 MessageQueue::waitMessage函数退出等待
}
return true;
}
对应的在 SurfaceFlinger::threadLoop
------>handleConsoleEvents
void SurfaceFlinger::handleConsoleEvents()
{
// something to do with the console
const DisplayHardware& hw = graphicPlane(0).displayHardware();
int what = android_atomic_and(0, &mConsoleSignals);
if (what & eConsoleAcquired) {
hw.acquireScreen();
----->mScreenAcquired = true;
// this is a temporary work-around, eventually this should be called
// by the power-manager
SurfaceFlinger::turnElectronBeamOn(mElectronBeamAnimationMode);
}
if (what & eConsoleReleased) {
if (hw.isScreenAcquired()) {
----->return mScreenAcquired;
hw.releaseScreen();
----->mBarrier.open();
----->mScreenAcquired = false;
}
}
mDirtyRegion.set(hw.bounds());
}
{
int err = 0;
char buf;
int fd;
fd = open(kSleepFileName, O_RDONLY, 0);
do {
err = read(fd, &buf, 1);
} while (err < 0 && errno == EINTR);
close(fd);
LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
if (err >= 0) {
sp<SurfaceFlinger> flinger = mFlinger.promote();
LOGD("About to give-up screen, flinger = %p", flinger.get());
if (flinger != 0) {
mBarrier.close();
flinger->screenReleased(0);
----->android_atomic_or(eConsoleReleased, &mConsoleSignals);
----->mEventQueue.invalidate();
----->mCondition.signal();// 这会使得 MessageQueue::waitMessage函数退出等待
mBarrier.wait();//等待
}
}
fd = open(kWakeFileName, O_RDONLY, 0);
do {
err = read(fd, &buf, 1);
} while (err < 0 && errno == EINTR);
close(fd);
LOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
if (err >= 0) {
sp<SurfaceFlinger> flinger = mFlinger.promote();
LOGD("Screen about to return, flinger = %p", flinger.get());
if (flinger != 0)
flinger->screenAcquired(0);
----->android_atomic_or(eConsoleAcquired, &mConsoleSignals);
----->mEventQueue.invalidate();
----->mCondition.signal();// 这会使得 MessageQueue::waitMessage函数退出等待
}
return true;
}
对应的在 SurfaceFlinger::threadLoop
------>handleConsoleEvents
void SurfaceFlinger::handleConsoleEvents()
{
// something to do with the console
const DisplayHardware& hw = graphicPlane(0).displayHardware();
int what = android_atomic_and(0, &mConsoleSignals);
if (what & eConsoleAcquired) {
hw.acquireScreen();
----->mScreenAcquired = true;
// this is a temporary work-around, eventually this should be called
// by the power-manager
SurfaceFlinger::turnElectronBeamOn(mElectronBeamAnimationMode);
}
if (what & eConsoleReleased) {
if (hw.isScreenAcquired()) {
----->return mScreenAcquired;
hw.releaseScreen();
----->mBarrier.open();
----->mScreenAcquired = false;
}
}
mDirtyRegion.set(hw.bounds());
}
SurfaceFlinger是在初始化函数readToRun的时候创建了
DisplayHardware实例,在构造该实例的过程中,该实例又启动了新的线程
DisplayEventThread,该线程与SurfaceFlinger
主线程之间,交替切换运行。
DisplayEventThread线程首先读取kSleepFileName文件,并读取一个字节的内容,然后通知
SurfaceFlinger释放屏幕,SurfaceFlinger->screenReleased
函数将使得
SurfaceFlinger::threadLoop中的waitForEvent
函数退出消息等待,并把
SurfaceFlinger的Signal
设置为eConsoleReleased,然后
DisplayEventThread线程调用mBarrier.wait()
进入等待状态。
SurfaceFlinger::threadLoop函数从waitForEvent
退出后,进入
handleConsoleEvents函数,检测到eConsoleReleased信号,由于默认情况下,
DisplayHardware中的mScreenAcquired
为true,将会执行
hw.releaseScreen(),也就是说,DisplayEventThread线程将会被激活,但是由于它的优先级与
SurfaceFilinger的主线程的优先级是一样的,所以不会抢占主线程运行。这样看来,这两个线程不断的交替运行,
mScreenAcquired不断的被设置为true和
false,那么它的作用是什么呢?在
threadLoop函数里,使用DisplayHardware::canDraw来判断是否进行画的动作,这个
canDraw就是返回mScreenAcquired
,这样看来,通过
DisplayEventThread线程主要是让主线程的消息队列处理能定期退出,交给
DispayHardware来画屏幕。
3.DisplayHardware的初始化
void DisplayHardware::init(uint32_t dpy)
{
mNativeWindow = new FramebufferNativeWindow();------<1>------
framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
if (!fbDev) {
LOGE("Display subsystem failed to initialize. check logs. exiting...");
exit(0);
}
int format;
ANativeWindow const * const window = mNativeWindow.get();
window->query(window, NATIVE_WINDOW_FORMAT, &format);
mDpiX = mNativeWindow->xdpi;
mDpiY = mNativeWindow->ydpi;
mRefreshRate = fbDev->fps;
EGLint w, h, dummy;
EGLint numConfigs=0;
EGLSurface surface;
EGLContext context;
EGLBoolean result;
status_t err;
// initialize EGL
EGLint attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE, 0,
EGL_NONE
};
// debug: disable h/w rendering
char property[PROPERTY_VALUE_MAX];
if (property_get("debug.sf.hw", property, NULL) > 0) {
if (atoi(property) == 0) {
LOGW("H/W composition disabled");
attribs[2] = EGL_CONFIG_CAVEAT;
attribs[3] = EGL_SLOW_CONFIG;
}
}
// TODO: all the extensions below should be queried through
// eglGetProcAddress().
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, NULL, NULL);
eglGetConfigs(display, NULL, 0, &numConfigs);
EGLConfig config = NULL;
err = selectConfigForPixelFormat(display, attribs, format, &config);
LOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
EGLint r,g,b,a;
eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
if (mNativeWindow->isUpdateOnDemand()) {
mFlags |= PARTIAL_UPDATES;
}
if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
if (dummy == EGL_SLOW_CONFIG)
mFlags |= SLOW_CONFIG;
}
/*
* Create our main surface
*/
surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
eglQuerySurface(display, surface, EGL_WIDTH, &mWidth);
eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
if (mFlags & PARTIAL_UPDATES) {
// if we have partial updates, we definitely don't need to
// preserve the backbuffer, which may be costly.
eglSurfaceAttrib(display, surface,
EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
}
if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
if (dummy == EGL_BUFFER_PRESERVED) {
mFlags |= BUFFER_PRESERVED;
}
}
/* Read density from build-specific ro.sf.lcd_density property
* except if it is overridden by qemu.sf.lcd_density.
*/
if (property_get("qemu.sf.lcd_density", property, NULL) <= 0) {
if (property_get("ro.sf.lcd_density", property, NULL) <= 0) {
LOGW("ro.sf.lcd_density not defined, using 160 dpi by default.");
strcpy(property, "160");
}
} else {
/* for the emulator case, reset the dpi values too */
mDpiX = mDpiY = atoi(property);
}
mDensity = atoi(property) * (1.0f/160.0f);
/*
* Create our OpenGL ES context
*/
EGLint contextAttributes[] = {
#ifdef EGL_IMG_context_priority
#ifdef HAS_CONTEXT_PRIORITY
#warning "using EGL_IMG_context_priority"
EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,
#endif
#endif
EGL_NONE, EGL_NONE
};
context = eglCreateContext(display, config, NULL, contextAttributes);
mDisplay = display;
mConfig = config;
mSurface = surface;
mContext = context;
mFormat = fbDev->format;
mPageFlipCount = 0;
/*
* Gather OpenGL ES extensions
*/
result = eglMakeCurrent(display, surface, surface, context);
if (!result) {
LOGE("Couldn't create a working GLES context. check logs. exiting...");
exit(0);
}
GLExtensions& extensions(GLExtensions::getInstance());
extensions.initWithGLStrings(
glGetString(GL_VENDOR),
glGetString(GL_RENDERER),
glGetString(GL_VERSION),
glGetString(GL_EXTENSIONS),
eglQueryString(display, EGL_VENDOR),
eglQueryString(display, EGL_VERSION),
eglQueryString(display, EGL_EXTENSIONS));
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
#ifdef EGL_ANDROID_swap_rectangle
if (extensions.hasExtension("EGL_ANDROID_swap_rectangle")) {
if (eglSetSwapRectangleANDROID(display, surface,
0, 0, mWidth, mHeight) == EGL_TRUE) {
// This could fail if this extension is not supported by this
// specific surface (of config)
mFlags |= SWAP_RECTANGLE;
}
}
// when we have the choice between PARTIAL_UPDATES and SWAP_RECTANGLE
// choose PARTIAL_UPDATES, which should be more efficient
if (mFlags & PARTIAL_UPDATES)
mFlags &= ~SWAP_RECTANGLE;
#endif
LOGI("EGL informations:");
LOGI("# of configs : %d", numConfigs);
LOGI("vendor : %s", extensions.getEglVendor());
LOGI("version : %s", extensions.getEglVersion());
LOGI("extensions: %s", extensions.getEglExtension());
LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
LOGI("OpenGL informations:");
LOGI("vendor : %s", extensions.getVendor());
LOGI("renderer : %s", extensions.getRenderer());
LOGI("version : %s", extensions.getVersion());
LOGI("extensions: %s", extensions.getExtension());
LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
LOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]);
LOGI("flags = %08x", mFlags);
// Unbind the context from this thread
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
// initialize the H/W composer
mHwc = new HWComposer(mFlinger);
if (mHwc->initCheck() == NO_ERROR) {
mHwc->setFrameBuffer(mDisplay, mSurface);
}
}
代码分析如下:
{
mNativeWindow = new FramebufferNativeWindow();------<1>------
framebuffer_device_t const * fbDev = mNativeWindow->getDevice();
if (!fbDev) {
LOGE("Display subsystem failed to initialize. check logs. exiting...");
exit(0);
}
int format;
ANativeWindow const * const window = mNativeWindow.get();
window->query(window, NATIVE_WINDOW_FORMAT, &format);
mDpiX = mNativeWindow->xdpi;
mDpiY = mNativeWindow->ydpi;
mRefreshRate = fbDev->fps;
EGLint w, h, dummy;
EGLint numConfigs=0;
EGLSurface surface;
EGLContext context;
EGLBoolean result;
status_t err;
// initialize EGL
EGLint attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE, 0,
EGL_NONE
};
// debug: disable h/w rendering
char property[PROPERTY_VALUE_MAX];
if (property_get("debug.sf.hw", property, NULL) > 0) {
if (atoi(property) == 0) {
LOGW("H/W composition disabled");
attribs[2] = EGL_CONFIG_CAVEAT;
attribs[3] = EGL_SLOW_CONFIG;
}
}
// TODO: all the extensions below should be queried through
// eglGetProcAddress().
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, NULL, NULL);
eglGetConfigs(display, NULL, 0, &numConfigs);
EGLConfig config = NULL;
err = selectConfigForPixelFormat(display, attribs, format, &config);
LOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
EGLint r,g,b,a;
eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
if (mNativeWindow->isUpdateOnDemand()) {
mFlags |= PARTIAL_UPDATES;
}
if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) {
if (dummy == EGL_SLOW_CONFIG)
mFlags |= SLOW_CONFIG;
}
/*
* Create our main surface
*/
surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
eglQuerySurface(display, surface, EGL_WIDTH, &mWidth);
eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight);
if (mFlags & PARTIAL_UPDATES) {
// if we have partial updates, we definitely don't need to
// preserve the backbuffer, which may be costly.
eglSurfaceAttrib(display, surface,
EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
}
if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
if (dummy == EGL_BUFFER_PRESERVED) {
mFlags |= BUFFER_PRESERVED;
}
}
/* Read density from build-specific ro.sf.lcd_density property
* except if it is overridden by qemu.sf.lcd_density.
*/
if (property_get("qemu.sf.lcd_density", property, NULL) <= 0) {
if (property_get("ro.sf.lcd_density", property, NULL) <= 0) {
LOGW("ro.sf.lcd_density not defined, using 160 dpi by default.");
strcpy(property, "160");
}
} else {
/* for the emulator case, reset the dpi values too */
mDpiX = mDpiY = atoi(property);
}
mDensity = atoi(property) * (1.0f/160.0f);
/*
* Create our OpenGL ES context
*/
EGLint contextAttributes[] = {
#ifdef EGL_IMG_context_priority
#ifdef HAS_CONTEXT_PRIORITY
#warning "using EGL_IMG_context_priority"
EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,
#endif
#endif
EGL_NONE, EGL_NONE
};
context = eglCreateContext(display, config, NULL, contextAttributes);
mDisplay = display;
mConfig = config;
mSurface = surface;
mContext = context;
mFormat = fbDev->format;
mPageFlipCount = 0;
/*
* Gather OpenGL ES extensions
*/
result = eglMakeCurrent(display, surface, surface, context);
if (!result) {
LOGE("Couldn't create a working GLES context. check logs. exiting...");
exit(0);
}
GLExtensions& extensions(GLExtensions::getInstance());
extensions.initWithGLStrings(
glGetString(GL_VENDOR),
glGetString(GL_RENDERER),
glGetString(GL_VERSION),
glGetString(GL_EXTENSIONS),
eglQueryString(display, EGL_VENDOR),
eglQueryString(display, EGL_VERSION),
eglQueryString(display, EGL_EXTENSIONS));
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
#ifdef EGL_ANDROID_swap_rectangle
if (extensions.hasExtension("EGL_ANDROID_swap_rectangle")) {
if (eglSetSwapRectangleANDROID(display, surface,
0, 0, mWidth, mHeight) == EGL_TRUE) {
// This could fail if this extension is not supported by this
// specific surface (of config)
mFlags |= SWAP_RECTANGLE;
}
}
// when we have the choice between PARTIAL_UPDATES and SWAP_RECTANGLE
// choose PARTIAL_UPDATES, which should be more efficient
if (mFlags & PARTIAL_UPDATES)
mFlags &= ~SWAP_RECTANGLE;
#endif
LOGI("EGL informations:");
LOGI("# of configs : %d", numConfigs);
LOGI("vendor : %s", extensions.getEglVendor());
LOGI("version : %s", extensions.getEglVersion());
LOGI("extensions: %s", extensions.getEglExtension());
LOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
LOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
LOGI("OpenGL informations:");
LOGI("vendor : %s", extensions.getVendor());
LOGI("renderer : %s", extensions.getRenderer());
LOGI("version : %s", extensions.getVersion());
LOGI("extensions: %s", extensions.getExtension());
LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
LOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]);
LOGI("flags = %08x", mFlags);
// Unbind the context from this thread
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
// initialize the H/W composer
mHwc = new HWComposer(mFlinger);
if (mHwc->initCheck() == NO_ERROR) {
mHwc->setFrameBuffer(mDisplay, mSurface);
}
}
代码分析如下:
FramebufferNativeWindow
class FramebufferNativeWindow
: public EGLNativeBase<
ANativeWindow,
FramebufferNativeWindow,
LightRefBase<FramebufferNativeWindow> >
FramebufferNativeWindow继承自 ANativeWindow,其构造函数如下:
FramebufferNativeWindow::FramebufferNativeWindow()
: BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
{
hw_module_t const* module;
if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {//得到gralloc 模块
int stride;
int err;
int i;
err = framebuffer_open(module, &fbDev);//从模块中得到fb设备
LOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
err = gralloc_open(module, &grDev);//从模块中得到gpu0设备,前面已经分析过
LOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));
// bail out if we can't initialize the modules
if (!fbDev || !grDev)
return;
mUpdateOnDemand = (fbDev->setUpdateRect != 0);
// initialize the buffer FIFO
mNumBuffers = NUM_FRAME_BUFFERS;
mNumFreeBuffers = NUM_FRAME_BUFFERS;
mBufferHead = mNumBuffers-1;
//创建两个 native buffer
for (i = 0; i < mNumBuffers; i++)
{
buffers[i] = new NativeBuffer(
fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
}
//为 native buffer分配内存,由于使用了GRALLOC_USAGE_HW_FB,所以是从 framebuffer中分配的,而不是从asmem中分配的
for (i = 0; i < mNumBuffers; i++)
{
err = grDev->alloc(grDev,
fbDev->width, fbDev->height, fbDev->format,
GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);
LOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",
i, fbDev->width, fbDev->height, strerror(-err));
if (err)
{
mNumBuffers = i;
mNumFreeBuffers = i;
mBufferHead = mNumBuffers-1;
break;
}
}
const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
const_cast<int&>(ANativeWindow::minSwapInterval) =
fbDev->minSwapInterval;
const_cast<int&>(ANativeWindow::maxSwapInterval) =
fbDev->maxSwapInterval;
} else {
LOGE("Couldn't get gralloc module");
}
ANativeWindow::setSwapInterval = setSwapInterval;
ANativeWindow::dequeueBuffer = dequeueBuffer;
ANativeWindow::lockBuffer = lockBuffer;
ANativeWindow::queueBuffer = queueBuffer;
ANativeWindow::query = query;
ANativeWindow::perform = perform;
}
先来看 framebuffer_open函数,它定义于hardware/libhardware/include/hardware/fb.h,它实际调用了hardware/libhardware/modules/gralloc/framebuffer.cpp文件中的fb_device_open 函数
: public EGLNativeBase<
ANativeWindow,
FramebufferNativeWindow,
LightRefBase<FramebufferNativeWindow> >
FramebufferNativeWindow继承自 ANativeWindow,其构造函数如下:
FramebufferNativeWindow::FramebufferNativeWindow()
: BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
{
hw_module_t const* module;
if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {//得到gralloc 模块
int stride;
int err;
int i;
err = framebuffer_open(module, &fbDev);//从模块中得到fb设备
LOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
err = gralloc_open(module, &grDev);//从模块中得到gpu0设备,前面已经分析过
LOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));
// bail out if we can't initialize the modules
if (!fbDev || !grDev)
return;
mUpdateOnDemand = (fbDev->setUpdateRect != 0);
// initialize the buffer FIFO
mNumBuffers = NUM_FRAME_BUFFERS;
mNumFreeBuffers = NUM_FRAME_BUFFERS;
mBufferHead = mNumBuffers-1;
//创建两个 native buffer
for (i = 0; i < mNumBuffers; i++)
{
buffers[i] = new NativeBuffer(
fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
}
//为 native buffer分配内存,由于使用了GRALLOC_USAGE_HW_FB,所以是从 framebuffer中分配的,而不是从asmem中分配的
for (i = 0; i < mNumBuffers; i++)
{
err = grDev->alloc(grDev,
fbDev->width, fbDev->height, fbDev->format,
GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);
LOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",
i, fbDev->width, fbDev->height, strerror(-err));
if (err)
{
mNumBuffers = i;
mNumFreeBuffers = i;
mBufferHead = mNumBuffers-1;
break;
}
}
const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
const_cast<int&>(ANativeWindow::minSwapInterval) =
fbDev->minSwapInterval;
const_cast<int&>(ANativeWindow::maxSwapInterval) =
fbDev->maxSwapInterval;
} else {
LOGE("Couldn't get gralloc module");
}
ANativeWindow::setSwapInterval = setSwapInterval;
ANativeWindow::dequeueBuffer = dequeueBuffer;
ANativeWindow::lockBuffer = lockBuffer;
ANativeWindow::queueBuffer = queueBuffer;
ANativeWindow::query = query;
ANativeWindow::perform = perform;
}
先来看 framebuffer_open函数,它定义于hardware/libhardware/include/hardware/fb.h,它实际调用了hardware/libhardware/modules/gralloc/framebuffer.cpp文件中的fb_device_open 函数
fb_device_open
int fb_device_open(hw_module_t const* module, const char* name,
hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
alloc_device_t* gralloc_device;
status = gralloc_open(module, &gralloc_device);
if (status < 0)
return status;
/* initialize our state here */
fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
/* initialize the procs */
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = const_cast<hw_module_t*>(module);
dev->device.common.close = fb_close;
dev->device.setSwapInterval = fb_setSwapInterval;
dev->device.post = fb_post;
dev->device.setUpdateRect = 0;
private_module_t* m = (private_module_t*)module;
status = mapFrameBuffer(m);
if (status >= 0) {
int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
int format = (m->info.bits_per_pixel == 32)
? HAL_PIXEL_FORMAT_RGBX_8888
: HAL_PIXEL_FORMAT_RGB_565;
const_cast<uint32_t&>(dev->device.flags) = 0;
const_cast<uint32_t&>(dev->device.width) = m->info.xres;
const_cast<uint32_t&>(dev->device.height) = m->info.yres;
const_cast<int&>(dev->device.stride) = stride;
const_cast<int&>(dev->device.format) = format;
const_cast<float&>(dev->device.xdpi) = m->xdpi;
const_cast<float&>(dev->device.ydpi) = m->ydpi;
const_cast<float&>(dev->device.fps) = m->fps;
const_cast<int&>(dev->device.minSwapInterval) = 1;
const_cast<int&>(dev->device.maxSwapInterval) = 1;
*device = &dev->device.common;
}
}
return status;
}
这个函数中最终要的是调用了 mapFrameBuffer函数,它有调用了mapFrameBufferLocked
hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
alloc_device_t* gralloc_device;
status = gralloc_open(module, &gralloc_device);
if (status < 0)
return status;
/* initialize our state here */
fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
/* initialize the procs */
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = const_cast<hw_module_t*>(module);
dev->device.common.close = fb_close;
dev->device.setSwapInterval = fb_setSwapInterval;
dev->device.post = fb_post;
dev->device.setUpdateRect = 0;
private_module_t* m = (private_module_t*)module;
status = mapFrameBuffer(m);
if (status >= 0) {
int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
int format = (m->info.bits_per_pixel == 32)
? HAL_PIXEL_FORMAT_RGBX_8888
: HAL_PIXEL_FORMAT_RGB_565;
const_cast<uint32_t&>(dev->device.flags) = 0;
const_cast<uint32_t&>(dev->device.width) = m->info.xres;
const_cast<uint32_t&>(dev->device.height) = m->info.yres;
const_cast<int&>(dev->device.stride) = stride;
const_cast<int&>(dev->device.format) = format;
const_cast<float&>(dev->device.xdpi) = m->xdpi;
const_cast<float&>(dev->device.ydpi) = m->ydpi;
const_cast<float&>(dev->device.fps) = m->fps;
const_cast<int&>(dev->device.minSwapInterval) = 1;
const_cast<int&>(dev->device.maxSwapInterval) = 1;
*device = &dev->device.common;
}
}
return status;
}
这个函数中最终要的是调用了 mapFrameBuffer函数,它有调用了mapFrameBufferLocked
mapFrameBufferLocked
int mapFrameBufferLocked(struct private_module_t* module)
{
// already initialized...
if (module->framebuffer) {
return 0;
}
//这里是 graphic设备的两个可能的路径
char const * const device_template[] = {
"/dev/graphics/fb%u",
"/dev/fb%u",
0 };
int fd = -1;
int i=0;
char name[64];
//这里从设备得到 fd
while ((fd==-1) && device_template[i]) {
snprintf(name, 64, device_template[i], 0);
fd = open(name, O_RDWR, 0);
i++;
}
if (fd < 0)
return -errno;
struct fb_fix_screeninfo finfo;
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
return -errno;
struct fb_var_screeninfo info;
if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
return -errno;
info.reserved[0] = 0;
info.reserved[1] = 0;
info.reserved[2] = 0;
info.xoffset = 0;
info.yoffset = 0;
info.activate = FB_ACTIVATE_NOW;
/*
* Request NUM_BUFFERS screens (at lest 2 for page flipping)
*/
//yres_virtual是 y轴的虚拟值,如果我们是 page flipping,那么虚拟高度就是实际高度的两倍, yres是实际高度
info.yres_virtual = info.yres * NUM_BUFFERS;
uint32_t flags = PAGE_FLIP;
//把虚拟高度设置给设备
if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
info.yres_virtual = info.yres;
flags &= ~PAGE_FLIP;
LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
}
if (info.yres_virtual < info.yres * 2) {
// we need at least 2 for page-flipping
info.yres_virtual = info.yres;
flags &= ~PAGE_FLIP;
LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
info.yres_virtual, info.yres*2);
}
if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
return -errno;
uint64_t refreshQuotient =
(
uint64_t( info.upper_margin + info.lower_margin + info.yres )
* ( info.left_margin + info.right_margin + info.xres )
* info.pixclock
);
/* Beware, info.pixclock might be 0 under emulation, so avoid a
* division-by-0 here (SIGFPE on ARM) */
int refreshRate = refreshQuotient > 0 ? (int)(1000000000000000LLU / refreshQuotient) : 0;
if (refreshRate == 0) {
// bleagh, bad info from the driver
refreshRate = 60*1000; // 60 Hz
}
if (int(info.width) <= 0 || int(info.height) <= 0) {
// the driver doesn't return that information
// default to 160 dpi
info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
}
//info.width和 info.height是设备的宽度和高度,他们是以 mm为单位的,infor.xres 和info.yres也是设备的宽度和高度,不过他们是以像素为单位的, 1inch=25.4mm
float xdpi = (info.xres * 25.4f) / info.width;
float ydpi = (info.yres * 25.4f) / info.height;
float fps = refreshRate / 1000.0f;//fps是每秒的帧数
LOGI( "using (fd=%d)\n"
"id = %s\n"
"xres = %d px\n"
"yres = %d px\n"
"xres_virtual = %d px\n"
"yres_virtual = %d px\n"
"bpp = %d\n"
"r = %2u:%u\n"
"g = %2u:%u\n"
"b = %2u:%u\n",
fd,
finfo.id,
info.xres,
info.yres,
info.xres_virtual,
info.yres_virtual,
info.bits_per_pixel,
info.red.offset, info.red.length,
info.green.offset, info.green.length,
info.blue.offset, info.blue.length
);
LOGI( "width = %d mm (%f dpi)\n"
"height = %d mm (%f dpi)\n"
"refresh rate = %.2f Hz\n",
info.width, xdpi,
info.height, ydpi,
fps
);
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
return -errno;
if (finfo.smem_len <= 0)
return -errno;
module->flags = flags;
module->info = info;
module->finfo = finfo;
module->xdpi = xdpi;
module->ydpi = ydpi;
module->fps = fps;
/*
* map the framebuffer
*/
int err;
size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);
module->framebuffer = new private_handle_t(dup(fd), fbSize, 0);
module->numBuffers = info.yres_virtual / info.yres;
module->bufferMask = 0;
void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (vaddr == MAP_FAILED) {
LOGE("Error mapping the framebuffer (%s)", strerror(errno));
return -errno;
}
module->framebuffer->base = intptr_t(vaddr);
memset(vaddr, 0, fbSize);
return 0;
}
fb_device_open在调用该函数之后,得到了显示设备的详细信息,并存储在 fb_context_t结构中返回,同时显示设备文件被映射到内存中,并创建了 frambuffer,这个frambuffer 的handle存储在 module中。
{
// already initialized...
if (module->framebuffer) {
return 0;
}
//这里是 graphic设备的两个可能的路径
char const * const device_template[] = {
"/dev/graphics/fb%u",
"/dev/fb%u",
0 };
int fd = -1;
int i=0;
char name[64];
//这里从设备得到 fd
while ((fd==-1) && device_template[i]) {
snprintf(name, 64, device_template[i], 0);
fd = open(name, O_RDWR, 0);
i++;
}
if (fd < 0)
return -errno;
struct fb_fix_screeninfo finfo;
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
return -errno;
struct fb_var_screeninfo info;
if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
return -errno;
info.reserved[0] = 0;
info.reserved[1] = 0;
info.reserved[2] = 0;
info.xoffset = 0;
info.yoffset = 0;
info.activate = FB_ACTIVATE_NOW;
/*
* Request NUM_BUFFERS screens (at lest 2 for page flipping)
*/
//yres_virtual是 y轴的虚拟值,如果我们是 page flipping,那么虚拟高度就是实际高度的两倍, yres是实际高度
info.yres_virtual = info.yres * NUM_BUFFERS;
uint32_t flags = PAGE_FLIP;
//把虚拟高度设置给设备
if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
info.yres_virtual = info.yres;
flags &= ~PAGE_FLIP;
LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
}
if (info.yres_virtual < info.yres * 2) {
// we need at least 2 for page-flipping
info.yres_virtual = info.yres;
flags &= ~PAGE_FLIP;
LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
info.yres_virtual, info.yres*2);
}
if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
return -errno;
uint64_t refreshQuotient =
(
uint64_t( info.upper_margin + info.lower_margin + info.yres )
* ( info.left_margin + info.right_margin + info.xres )
* info.pixclock
);
/* Beware, info.pixclock might be 0 under emulation, so avoid a
* division-by-0 here (SIGFPE on ARM) */
int refreshRate = refreshQuotient > 0 ? (int)(1000000000000000LLU / refreshQuotient) : 0;
if (refreshRate == 0) {
// bleagh, bad info from the driver
refreshRate = 60*1000; // 60 Hz
}
if (int(info.width) <= 0 || int(info.height) <= 0) {
// the driver doesn't return that information
// default to 160 dpi
info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
}
//info.width和 info.height是设备的宽度和高度,他们是以 mm为单位的,infor.xres 和info.yres也是设备的宽度和高度,不过他们是以像素为单位的, 1inch=25.4mm
float xdpi = (info.xres * 25.4f) / info.width;
float ydpi = (info.yres * 25.4f) / info.height;
float fps = refreshRate / 1000.0f;//fps是每秒的帧数
LOGI( "using (fd=%d)\n"
"id = %s\n"
"xres = %d px\n"
"yres = %d px\n"
"xres_virtual = %d px\n"
"yres_virtual = %d px\n"
"bpp = %d\n"
"r = %2u:%u\n"
"g = %2u:%u\n"
"b = %2u:%u\n",
fd,
finfo.id,
info.xres,
info.yres,
info.xres_virtual,
info.yres_virtual,
info.bits_per_pixel,
info.red.offset, info.red.length,
info.green.offset, info.green.length,
info.blue.offset, info.blue.length
);
LOGI( "width = %d mm (%f dpi)\n"
"height = %d mm (%f dpi)\n"
"refresh rate = %.2f Hz\n",
info.width, xdpi,
info.height, ydpi,
fps
);
if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
return -errno;
if (finfo.smem_len <= 0)
return -errno;
module->flags = flags;
module->info = info;
module->finfo = finfo;
module->xdpi = xdpi;
module->ydpi = ydpi;
module->fps = fps;
/*
* map the framebuffer
*/
int err;
size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);
module->framebuffer = new private_handle_t(dup(fd), fbSize, 0);
module->numBuffers = info.yres_virtual / info.yres;
module->bufferMask = 0;
void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (vaddr == MAP_FAILED) {
LOGE("Error mapping the framebuffer (%s)", strerror(errno));
return -errno;
}
module->framebuffer->base = intptr_t(vaddr);
memset(vaddr, 0, fbSize);
return 0;
}
fb_device_open在调用该函数之后,得到了显示设备的详细信息,并存储在 fb_context_t结构中返回,同时显示设备文件被映射到内存中,并创建了 frambuffer,这个frambuffer 的handle存储在 module中。
gralloc_alloc_framebuffer_locked
在FramebufferNativeWindow构造函数中,同样打开了
GPU0设备,并从设备分配内存给
NativeuBuffer,这个分配过程不同于上面从
ashmem中分配的过程,它使用了
GRALLOC_USAGE_HW_FB usage。其分配过程如下:
static int gralloc_alloc_framebuffer_locked(alloc_device_t* dev,
size_t size, int usage, buffer_handle_t* pHandle)
{
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
// allocate the framebuffer
//从 module的framebuffer 中获取内存,如果这个 framebuffer为null ,需要进行分配
if (m->framebuffer == NULL) {
// initialize the framebuffer, the framebuffer is mapped once
// and forever.
int err = mapFrameBufferLocked(m);
if (err < 0) {
return err;
}
}
const uint32_t bufferMask = m->bufferMask;//buffermask是用来表示当前有哪些缓冲区得到使用
const uint32_t numBuffers = m->numBuffers;//当前使用了几个缓冲区,目前为 2
const size_t bufferSize = m->finfo.line_length * m->info.yres;//注意这里使用的是yres,也就是算出一个屏幕使用的内存大小
if (numBuffers == 1) {
// If we have only one buffer, we never use page-flipping. Instead,
// we return a regular buffer which will be memcpy'ed to the main
// screen when post is called.
int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;
return gralloc_alloc_buffer(dev, bufferSize, newUsage, pHandle);
}
if (bufferMask >= ((1LU<<numBuffers)-1)) {
// We ran out of buffers.
return -ENOMEM;
}
// create a "fake" handles for it
intptr_t vaddr = intptr_t(m->framebuffer->base);
private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), size,
private_handle_t::PRIV_FLAGS_FRAMEBUFFER);
// find a free slot
//从 mask中找到一个空前的位置,并根据序号算出这个 buffer的起始地址
for (uint32_t i=0 ; i<numBuffers ; i++) {
if ((bufferMask & (1LU<<i)) == 0) {
m->bufferMask |= (1LU<<i);
break;
}
vaddr += bufferSize;
}
hnd->base = vaddr;
hnd->offset = vaddr - intptr_t(m->framebuffer->base);//offset表示与原始地址的位移
*pHandle = hnd;
return 0;
}
这样,我们就为 NatvieBuffer分配了一块内存。综上所述, DisplayHardware::init的调用流程如下:
static int gralloc_alloc_framebuffer_locked(alloc_device_t* dev,
size_t size, int usage, buffer_handle_t* pHandle)
{
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
// allocate the framebuffer
//从 module的framebuffer 中获取内存,如果这个 framebuffer为null ,需要进行分配
if (m->framebuffer == NULL) {
// initialize the framebuffer, the framebuffer is mapped once
// and forever.
int err = mapFrameBufferLocked(m);
if (err < 0) {
return err;
}
}
const uint32_t bufferMask = m->bufferMask;//buffermask是用来表示当前有哪些缓冲区得到使用
const uint32_t numBuffers = m->numBuffers;//当前使用了几个缓冲区,目前为 2
const size_t bufferSize = m->finfo.line_length * m->info.yres;//注意这里使用的是yres,也就是算出一个屏幕使用的内存大小
if (numBuffers == 1) {
// If we have only one buffer, we never use page-flipping. Instead,
// we return a regular buffer which will be memcpy'ed to the main
// screen when post is called.
int newUsage = (usage & ~GRALLOC_USAGE_HW_FB) | GRALLOC_USAGE_HW_2D;
return gralloc_alloc_buffer(dev, bufferSize, newUsage, pHandle);
}
if (bufferMask >= ((1LU<<numBuffers)-1)) {
// We ran out of buffers.
return -ENOMEM;
}
// create a "fake" handles for it
intptr_t vaddr = intptr_t(m->framebuffer->base);
private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), size,
private_handle_t::PRIV_FLAGS_FRAMEBUFFER);
// find a free slot
//从 mask中找到一个空前的位置,并根据序号算出这个 buffer的起始地址
for (uint32_t i=0 ; i<numBuffers ; i++) {
if ((bufferMask & (1LU<<i)) == 0) {
m->bufferMask |= (1LU<<i);
break;
}
vaddr += bufferSize;
}
hnd->base = vaddr;
hnd->offset = vaddr - intptr_t(m->framebuffer->base);//offset表示与原始地址的位移
*pHandle = hnd;
return 0;
}
这样,我们就为 NatvieBuffer分配了一块内存。综上所述, DisplayHardware::init的调用流程如下:
DisplayHardware::init
----->new FramebufferNativeWindow
----->framebuffer_open
----->fb_device_open(hw_module_t const* module, const char* name,hw_device_t** device)
----->mapFrameBuffer
----->mapFrameBufferLocked(struct private_module_t* module)
----->gralloc_open
----->gralloc_alloc_framebuffer
----->gralloc_alloc_framebuffer_locked(alloc_device_t* dev,size_t size, int usage, buffer_handle_t* pHandle)
----->EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
----->surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
----->context = eglCreateContext(display, config, NULL, contextAttributes);
----->result = eglMakeCurrent(display, surface, surface, context);
----->eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
----->surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
----->context = eglCreateContext(display, config, NULL, contextAttributes);
----->result = eglMakeCurrent(display, surface, surface, context);
----->eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
这里涉及了几个概念,
nativewindow,surface
,context,
display,其中ANativeWindow
是android与
opengl es的接口结构,两边都在使用,在创建
Surface的时候,就会根据opengl
es的版本不同,创建不同的
suface结构,并把ANativeWindow
中关于设备的详细信息设置到这个
surface中,surface
的很多操作都是基于
ANativeWindow提供的函数的。surface显然是一个显示窗口的逻辑概念,
display代表显示设备,context是显示的环境,
makecurrent把display
,surface,
context联系到一起,并把context
bind到当前的进程。
4.DisplayHardware::flip
它调用了
eglSwapBuffers
frameworks/base/opengl/libagl2/src/egl.cpp
eglSwapBuffers
----->egl_surface_t::swapBuffers
frameworks/base/opengl/libagl2/src/egl.cpp
eglSwapBuffers
----->egl_surface_t::swapBuffers
----->previousBuffer = buffer;
----->nativeWindow->queueBuffer(nativeWindow, buffer);
----->FramebufferNativeWindow::queueBuffer
----->fp_post(hardware/libhardware/modules/gralloc/framebuffer.cpp)
----->FramebufferNativeWindow::queueBuffer
----->fp_post(hardware/libhardware/modules/gralloc/framebuffer.cpp)
----->nativeWindow->dequeueBuffer(nativeWindow, &buffer)
----->egl_surface_t::bindDrawSurface
----->gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &buffer);
从这些调用流程就可以看出, swapbuffer就是把当前的buffer,记录为 previousBuffer,然后把buffer 放回nativewindow,这里其实有一个 post buffer的过程,最后从nativewindow中重新出队列一个 buffer,然后把这个buffer设置给 opengl,作为新的drawsurface buffer ,其中fb_post的代码如下:
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
{
if (private_handle_t::validate(buffer) < 0)
return -EINVAL;
fb_context_t* ctx = (fb_context_t*)dev;
private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer);
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
const size_t offset = hnd->base - m->framebuffer->base;
m->info.activate = FB_ACTIVATE_VBL;
m->info.yoffset = offset / m->finfo.line_length;
if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) {
LOGE("FBIOPUT_VSCREENINFO failed");
m->base.unlock(&m->base, buffer);
return -errno;
}
m->currentBuffer = buffer;
} else {
// If we can't do the page_flip, just copy the buffer to the front
// FIXME: use copybit HAL instead of memcpy
void* fb_vaddr;
void* buffer_vaddr;
m->base.lock(&m->base, m->framebuffer,
GRALLOC_USAGE_SW_WRITE_RARELY,
0, 0, m->info.xres, m->info.yres,
&fb_vaddr);
m->base.lock(&m->base, buffer,
GRALLOC_USAGE_SW_READ_RARELY,
0, 0, m->info.xres, m->info.yres,
&buffer_vaddr);
memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);
m->base.unlock(&m->base, buffer);
m->base.unlock(&m->base, m->framebuffer);
}
return 0;
}
由于我们在 alloc buffer的时候,在函数gralloc_alloc_framebuffer_locked中
private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), size,
private_handle_t::PRIV_FLAGS_FRAMEBUFFER);
所以,上面这段代码走的是 ioctl的流程,这个ioctl相信是让屏幕显示相应位置的内容。
----->gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &buffer);
从这些调用流程就可以看出, swapbuffer就是把当前的buffer,记录为 previousBuffer,然后把buffer 放回nativewindow,这里其实有一个 post buffer的过程,最后从nativewindow中重新出队列一个 buffer,然后把这个buffer设置给 opengl,作为新的drawsurface buffer ,其中fb_post的代码如下:
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
{
if (private_handle_t::validate(buffer) < 0)
return -EINVAL;
fb_context_t* ctx = (fb_context_t*)dev;
private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer);
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
const size_t offset = hnd->base - m->framebuffer->base;
m->info.activate = FB_ACTIVATE_VBL;
m->info.yoffset = offset / m->finfo.line_length;
if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) {
LOGE("FBIOPUT_VSCREENINFO failed");
m->base.unlock(&m->base, buffer);
return -errno;
}
m->currentBuffer = buffer;
} else {
// If we can't do the page_flip, just copy the buffer to the front
// FIXME: use copybit HAL instead of memcpy
void* fb_vaddr;
void* buffer_vaddr;
m->base.lock(&m->base, m->framebuffer,
GRALLOC_USAGE_SW_WRITE_RARELY,
0, 0, m->info.xres, m->info.yres,
&fb_vaddr);
m->base.lock(&m->base, buffer,
GRALLOC_USAGE_SW_READ_RARELY,
0, 0, m->info.xres, m->info.yres,
&buffer_vaddr);
memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);
m->base.unlock(&m->base, buffer);
m->base.unlock(&m->base, m->framebuffer);
}
return 0;
}
由于我们在 alloc buffer的时候,在函数gralloc_alloc_framebuffer_locked中
private_handle_t* hnd = new private_handle_t(dup(m->framebuffer->fd), size,
private_handle_t::PRIV_FLAGS_FRAMEBUFFER);
所以,上面这段代码走的是 ioctl的流程,这个ioctl相信是让屏幕显示相应位置的内容。
四.handlePageFlip函数
该函数主要是进行
Buffer flip的,即把画好的buffer
swap到屏幕上
void SurfaceFlinger::handlePageFlip()
{
bool visibleRegions = mVisibleRegionsDirty;
const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
visibleRegions |= lockPageFlip(currentLayers);
const DisplayHardware& hw = graphicPlane(0).displayHardware();
const Region screenRegion(hw.bounds());
if (visibleRegions) {
Region opaqueRegion;
computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);
/*
* rebuild the visible layer list
*/
const size_t count = currentLayers.size();
mVisibleLayersSortedByZ.clear();
mVisibleLayersSortedByZ.setCapacity(count);
for (size_t i=0 ; i<count ; i++) {
if (!currentLayers[i]->visibleRegionScreen.isEmpty())
mVisibleLayersSortedByZ.add(currentLayers[i]);
}
mWormholeRegion = screenRegion.subtract(opaqueRegion);
mVisibleRegionsDirty = false;
invalidateHwcGeometry();
}
unlockPageFlip(currentLayers);
mDirtyRegion.orSelf(getAndClearInvalidateRegion());
mDirtyRegion.andSelf(screenRegion);
}
void SurfaceFlinger::handlePageFlip()
{
bool visibleRegions = mVisibleRegionsDirty;
const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
visibleRegions |= lockPageFlip(currentLayers);
const DisplayHardware& hw = graphicPlane(0).displayHardware();
const Region screenRegion(hw.bounds());
if (visibleRegions) {
Region opaqueRegion;
computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);
/*
* rebuild the visible layer list
*/
const size_t count = currentLayers.size();
mVisibleLayersSortedByZ.clear();
mVisibleLayersSortedByZ.setCapacity(count);
for (size_t i=0 ; i<count ; i++) {
if (!currentLayers[i]->visibleRegionScreen.isEmpty())
mVisibleLayersSortedByZ.add(currentLayers[i]);
}
mWormholeRegion = screenRegion.subtract(opaqueRegion);
mVisibleRegionsDirty = false;
invalidateHwcGeometry();
}
unlockPageFlip(currentLayers);
mDirtyRegion.orSelf(getAndClearInvalidateRegion());
mDirtyRegion.andSelf(screenRegion);
}
1.State
在分析
handlePageFlip之前,需要说清楚SurfaceFlinger的两个成员变量
mDrawingState和mCurrentState
,它们都是
State类型的变量,State定义如下:
struct State {
State() {
orientation = ISurfaceComposer::eOrientationDefault;
freezeDisplay = 0;
}
LayerVector layersSortedByZ;
uint8_t orientation;
uint8_t orientationFlags;
uint8_t freezeDisplay;
};
其中 LayerVector是一个有序的Vector,其中存取的都是 LayerBase实例指针,排序的标准是 LayerBase类的z order 。
mDrawingState表示当前画在屏幕上的 State,而mCurrentState 则表示当前正在处理的 State,也就是说mDrawingState 是previous State。由于在执行 handlePageFlip之前,已经执行了handleTransaction函数,其中的 commitTransaction函数中已经把mCurrentState赋值给 mDrawingState,所以在handlePageFlip 中,mDrawingState已经是最新的要显示的 State。
struct State {
State() {
orientation = ISurfaceComposer::eOrientationDefault;
freezeDisplay = 0;
}
LayerVector layersSortedByZ;
uint8_t orientation;
uint8_t orientationFlags;
uint8_t freezeDisplay;
};
其中 LayerVector是一个有序的Vector,其中存取的都是 LayerBase实例指针,排序的标准是 LayerBase类的z order 。
mDrawingState表示当前画在屏幕上的 State,而mCurrentState 则表示当前正在处理的 State,也就是说mDrawingState 是previous State。由于在执行 handlePageFlip之前,已经执行了handleTransaction函数,其中的 commitTransaction函数中已经把mCurrentState赋值给 mDrawingState,所以在handlePageFlip 中,mDrawingState已经是最新的要显示的 State。
2.lockPageFlip
这个函数本身比较简单,就是遍历
mDrawingState中的LayerVector
中的LayerBase,然后调用这个实例的
lockPageFlip,所以关键是看这些实例的
lockPageFlip
void Layer::lockPageFlip(bool& recomputeVisibleRegions)
{
if (mQueuedFrames > 0) {-----<1>-----
// Capture the old state of the layer for comparisons later
const bool oldOpacity = isOpaque();
sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
// signal another event if we have more frames pending
if (android_atomic_dec(&mQueuedFrames) > 1) {-----<2>-----
mFlinger->signalEvent();
}
if (mSurfaceTexture->updateTexImage() < NO_ERROR) {-----<3>-----
// something happened!
recomputeVisibleRegions = true;
return;
}
// update the active buffer
mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
const Rect crop(mSurfaceTexture->getCurrentCrop());
const uint32_t transform(mSurfaceTexture->getCurrentTransform());
const uint32_t scalingMode(mSurfaceTexture->getCurrentScalingMode());
if ((crop != mCurrentCrop) ||
(transform != mCurrentTransform) ||
(scalingMode != mCurrentScalingMode))
{
mCurrentCrop = crop;
mCurrentTransform = transform;
mCurrentScalingMode = scalingMode;
mFlinger->invalidateHwcGeometry();
}
GLfloat textureMatrix[16];
mSurfaceTexture->getTransformMatrix(textureMatrix);
if (memcmp(textureMatrix, mTextureMatrix, sizeof(textureMatrix))) {
memcpy(mTextureMatrix, textureMatrix, sizeof(textureMatrix));
mFlinger->invalidateHwcGeometry();
}
uint32_t bufWidth = mActiveBuffer->getWidth();
uint32_t bufHeight = mActiveBuffer->getHeight();
if (oldActiveBuffer != NULL) {
if (bufWidth != uint32_t(oldActiveBuffer->width) ||
bufHeight != uint32_t(oldActiveBuffer->height)) {
mFlinger->invalidateHwcGeometry();
}
}
mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
if (oldOpacity != isOpaque()) {
recomputeVisibleRegions = true;
}
glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// update the layer size and release freeze-lock
const Layer::State& front(drawingState());
// FIXME: mPostedDirtyRegion = dirty & bounds
mPostedDirtyRegion.set(front.w, front.h);
if ((front.w != front.requested_w) ||
(front.h != front.requested_h))
{
// check that we received a buffer of the right size
// (Take the buffer's orientation into account)
if (mCurrentTransform & Transform::ROT_90) {
swap(bufWidth, bufHeight);
}
if (isFixedSize() ||
(bufWidth == front.requested_w &&
bufHeight == front.requested_h))
{
// Here we pretend the transaction happened by updating the
// current and drawing states. Drawing state is only accessed
// in this thread, no need to have it locked
Layer::State& editDraw(mDrawingState);
editDraw.w = editDraw.requested_w;
editDraw.h = editDraw.requested_h;
// We also need to update the current state so that we don't
// end-up doing too much work during the next transaction.
// NOTE: We actually don't need hold the transaction lock here
// because State::w and State::h are only accessed from
// this thread
Layer::State& editTemp(currentState());
editTemp.w = editDraw.w;
editTemp.h = editDraw.h;
// recompute visible region
recomputeVisibleRegions = true;
// we now have the correct size, unfreeze the screen
mFreezeLock.clear();
}
LOGD_IF(DEBUG_RESIZE,
"lockPageFlip : "
" (layer=%p), buffer (%ux%u, tr=%02x), "
"requested (%dx%d)",
this,
bufWidth, bufHeight, mCurrentTransform,
front.requested_w, front.requested_h);
}
}
}
void Layer::lockPageFlip(bool& recomputeVisibleRegions)
{
if (mQueuedFrames > 0) {-----<1>-----
// Capture the old state of the layer for comparisons later
const bool oldOpacity = isOpaque();
sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
// signal another event if we have more frames pending
if (android_atomic_dec(&mQueuedFrames) > 1) {-----<2>-----
mFlinger->signalEvent();
}
if (mSurfaceTexture->updateTexImage() < NO_ERROR) {-----<3>-----
// something happened!
recomputeVisibleRegions = true;
return;
}
// update the active buffer
mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
const Rect crop(mSurfaceTexture->getCurrentCrop());
const uint32_t transform(mSurfaceTexture->getCurrentTransform());
const uint32_t scalingMode(mSurfaceTexture->getCurrentScalingMode());
if ((crop != mCurrentCrop) ||
(transform != mCurrentTransform) ||
(scalingMode != mCurrentScalingMode))
{
mCurrentCrop = crop;
mCurrentTransform = transform;
mCurrentScalingMode = scalingMode;
mFlinger->invalidateHwcGeometry();
}
GLfloat textureMatrix[16];
mSurfaceTexture->getTransformMatrix(textureMatrix);
if (memcmp(textureMatrix, mTextureMatrix, sizeof(textureMatrix))) {
memcpy(mTextureMatrix, textureMatrix, sizeof(textureMatrix));
mFlinger->invalidateHwcGeometry();
}
uint32_t bufWidth = mActiveBuffer->getWidth();
uint32_t bufHeight = mActiveBuffer->getHeight();
if (oldActiveBuffer != NULL) {
if (bufWidth != uint32_t(oldActiveBuffer->width) ||
bufHeight != uint32_t(oldActiveBuffer->height)) {
mFlinger->invalidateHwcGeometry();
}
}
mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
if (oldOpacity != isOpaque()) {
recomputeVisibleRegions = true;
}
glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// update the layer size and release freeze-lock
const Layer::State& front(drawingState());
// FIXME: mPostedDirtyRegion = dirty & bounds
mPostedDirtyRegion.set(front.w, front.h);
if ((front.w != front.requested_w) ||
(front.h != front.requested_h))
{
// check that we received a buffer of the right size
// (Take the buffer's orientation into account)
if (mCurrentTransform & Transform::ROT_90) {
swap(bufWidth, bufHeight);
}
if (isFixedSize() ||
(bufWidth == front.requested_w &&
bufHeight == front.requested_h))
{
// Here we pretend the transaction happened by updating the
// current and drawing states. Drawing state is only accessed
// in this thread, no need to have it locked
Layer::State& editDraw(mDrawingState);
editDraw.w = editDraw.requested_w;
editDraw.h = editDraw.requested_h;
// We also need to update the current state so that we don't
// end-up doing too much work during the next transaction.
// NOTE: We actually don't need hold the transaction lock here
// because State::w and State::h are only accessed from
// this thread
Layer::State& editTemp(currentState());
editTemp.w = editDraw.w;
editTemp.h = editDraw.h;
// recompute visible region
recomputeVisibleRegions = true;
// we now have the correct size, unfreeze the screen
mFreezeLock.clear();
}
LOGD_IF(DEBUG_RESIZE,
"lockPageFlip : "
" (layer=%p), buffer (%ux%u, tr=%02x), "
"requested (%dx%d)",
this,
bufWidth, bufHeight, mCurrentTransform,
front.requested_w, front.requested_h);
}
}
}
<1>mQueuedFrames
首先说
mQueuedFrames这个成员变量,在lock的时候要求它大于
0,这个变量在初始化的时候等于
0,在onFrameQueued
函数中加一
void Layer::onFrameQueued() {
android_atomic_inc(&mQueuedFrames);
mFlinger->signalEvent();//该函数将使得消息队列返回一个 invalidate消息给SurfaceFlinger
}
这个onFrameQueued函数是注册给 Layer中的SurfaceTexture ,在有Frame的时候通知 layer的
void Layer::onFirstRef()
{
LayerBaseClient::onFirstRef();
struct FrameQueuedListener : public SurfaceTexture::FrameAvailableListener {
FrameQueuedListener(Layer* layer) : mLayer(layer) { }
private:
wp<Layer> mLayer;
virtual void onFrameAvailable() {
sp<Layer> that(mLayer.promote());
if (that != 0) {
that->onFrameQueued();
}
}
};
mSurfaceTexture = new SurfaceTextureLayer(mTextureName, this);
mSurfaceTexture->setFrameAvailableListener(new FrameQueuedListener(this));
mSurfaceTexture->setSynchronousMode(true);
mSurfaceTexture->setBufferCountServer(2);
}
在SurfaceTexture::queueBuffer中,有新的Buffer加入到队列中时候,调用 listener回调,通知Layer 有新的Frame了,这时 Layer中的mQueueFrames 将加一,同时还会退出消息处理, threadLoop有机会处理这个frame。有个特别需要注意的是,为什么使用android_atomic_inc来给mQueuedFrames加一,这是因为这个Layer::onFrameQueued是被SurfaceTexture 调用的,这个 SurfaceTexture实例是Binder 的服务器端,它在响应客户端请求,想自己的队列中添加frame的时候,实际上是运行在SurfaceFlinger进程的Binder线程中被调用,与 SurfaceFling的主线程不在同一个线程。
void Layer::onFrameQueued() {
android_atomic_inc(&mQueuedFrames);
mFlinger->signalEvent();//该函数将使得消息队列返回一个 invalidate消息给SurfaceFlinger
}
这个onFrameQueued函数是注册给 Layer中的SurfaceTexture ,在有Frame的时候通知 layer的
void Layer::onFirstRef()
{
LayerBaseClient::onFirstRef();
struct FrameQueuedListener : public SurfaceTexture::FrameAvailableListener {
FrameQueuedListener(Layer* layer) : mLayer(layer) { }
private:
wp<Layer> mLayer;
virtual void onFrameAvailable() {
sp<Layer> that(mLayer.promote());
if (that != 0) {
that->onFrameQueued();
}
}
};
mSurfaceTexture = new SurfaceTextureLayer(mTextureName, this);
mSurfaceTexture->setFrameAvailableListener(new FrameQueuedListener(this));
mSurfaceTexture->setSynchronousMode(true);
mSurfaceTexture->setBufferCountServer(2);
}
在SurfaceTexture::queueBuffer中,有新的Buffer加入到队列中时候,调用 listener回调,通知Layer 有新的Frame了,这时 Layer中的mQueueFrames 将加一,同时还会退出消息处理, threadLoop有机会处理这个frame。有个特别需要注意的是,为什么使用android_atomic_inc来给mQueuedFrames加一,这是因为这个Layer::onFrameQueued是被SurfaceTexture 调用的,这个 SurfaceTexture实例是Binder 的服务器端,它在响应客户端请求,想自己的队列中添加frame的时候,实际上是运行在SurfaceFlinger进程的Binder线程中被调用,与 SurfaceFling的主线程不在同一个线程。
<2>more frames
如果有多待处理的帧,需要再次退出消息处理给后面的代码机会处理。
<3>SurfaceTexture::updateTexImage
调用
SurfaceTexture::updateTexImage可以说是该函数最重要的代码了
status_t SurfaceTexture::updateTexImage() {
ST_LOGV("SurfaceTexture::updateTexImage");
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
ST_LOGE("calling updateTexImage() on an abandoned SurfaceTexture");
return NO_INIT;
}
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
if (!mQueue.empty()) {
Fifo::iterator front(mQueue.begin());
int buf = *front;
// Update the GL texture object.
EGLImageKHR image = mSlots[buf].mEglImage;
if (image == EGL_NO_IMAGE_KHR) {
EGLDisplay dpy = eglGetCurrentDisplay();
if (mSlots[buf].mGraphicBuffer == 0) {
ST_LOGE("buffer at slot %d is null", buf);
return BAD_VALUE;
}
image = createImage(dpy, mSlots[buf].mGraphicBuffer);
mSlots[buf].mEglImage = image;
mSlots[buf].mEglDisplay = dpy;
if (image == EGL_NO_IMAGE_KHR) {
// NOTE: if dpy was invalid, createImage() is guaranteed to
// fail. so we'd end up here.
return -EINVAL;
}
}
GLint error;
while ((error = glGetError()) != GL_NO_ERROR) {
ST_LOGW("updateTexImage: clearing GL error: %#04x", error);
}
glBindTexture(mTexTarget, mTexName);
glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
bool failed = false;
while ((error = glGetError()) != GL_NO_ERROR) {
ST_LOGE("error binding external texture image %p (slot %d): %#04x",
image, buf, error);
failed = true;
}
if (failed) {
return -EINVAL;
}
if (mCurrentTexture != INVALID_BUFFER_SLOT) {
// The current buffer becomes FREE if it was still in the queued
// state. If it has already been given to the client
// (synchronous mode), then it stays in DEQUEUED state.
if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED)
mSlots[mCurrentTexture].mBufferState = BufferSlot::FREE;
}
// Update the SurfaceTexture state.
mCurrentTexture = buf;
mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
mCurrentCrop = mSlots[buf].mCrop;
mCurrentTransform = mSlots[buf].mTransform;
mCurrentScalingMode = mSlots[buf].mScalingMode;
mCurrentTimestamp = mSlots[buf].mTimestamp;
computeCurrentTransformMatrix();
// Now that we've passed the point at which failures can happen,
// it's safe to remove the buffer from the front of the queue.
mQueue.erase(front);
mDequeueCondition.signal();
} else {
// We always bind the texture even if we don't update its contents.
glBindTexture(mTexTarget, mTexName);
}
return OK;
}
先说一下这个函数中的 mQueue,这个变量是Vector<int>类型,在 SurfaceTexture::queueBuffer函数中
status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp,
uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
。。。
if (mSynchronousMode) {
// In synchronous mode we queue all buffers in a FIFO.
mQueue.push_back(buf);
// Synchronous mode always signals that an additional frame should
// be consumed.
listener = mFrameAvailableListener;
} else {
// In asynchronous mode we only keep the most recent buffer.
if (mQueue.empty()) {
mQueue.push_back(buf);
// Asynchronous mode only signals that a frame should be
// consumed if no previous frame was pending. If a frame were
// pending then the consumer would have already been notified.
listener = mFrameAvailableListener;
} else {
Fifo::iterator front(mQueue.begin());
// buffer currently queued is freed
mSlots[*front].mBufferState = BufferSlot::FREE;
// and we record the new buffer index in the queued list
*front = buf;
}
}
。。。
}
在同步模式中, queueBuffer把buf 索引放到 mQueue中,表示这是需要处理的 buffer,在异步模式下,由于只需要存储最新的 buffer,所以从mQueue 中取出第一个 buffer的索引,将它对应的buffer的状态设置为 free,然后把新的索引放到队列中去。也就是说,在这种模式下, Queue中只有一个最新的buffer。
在updateTexImage中,判断 mQueue是否为空,也就是说这是一个读写队列,在 Binder线程中通过queueBuffer 把需要处理的 Buffer入队列,在SurfaceFlinger 的主线程中读取 Buffer。updateTexImage 中调用了 createImage函数,它实际上是根据读写队列中 buffer创建了OpenGL|ES 的image,这个 image被保存在相应的slot中。同时,下面两个函数把 image与Tex 绑定起来
glBindTexture(mTexTarget, mTexName);
glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
返回来再看 Layer::lockPageFlip函数,后面的代码就是计算一个 DirtyRegion,即要画image 的那一部分,在 Layer中,也有两个State, DrawingState和CurrentState ,这个State的结构与 SurfaceFlinger的State 结构不同,但是 DrawState同样表示当前已经在屏幕上的状态, CurrentState是当前处理的状态。
status_t SurfaceTexture::updateTexImage() {
ST_LOGV("SurfaceTexture::updateTexImage");
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
ST_LOGE("calling updateTexImage() on an abandoned SurfaceTexture");
return NO_INIT;
}
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
if (!mQueue.empty()) {
Fifo::iterator front(mQueue.begin());
int buf = *front;
// Update the GL texture object.
EGLImageKHR image = mSlots[buf].mEglImage;
if (image == EGL_NO_IMAGE_KHR) {
EGLDisplay dpy = eglGetCurrentDisplay();
if (mSlots[buf].mGraphicBuffer == 0) {
ST_LOGE("buffer at slot %d is null", buf);
return BAD_VALUE;
}
image = createImage(dpy, mSlots[buf].mGraphicBuffer);
mSlots[buf].mEglImage = image;
mSlots[buf].mEglDisplay = dpy;
if (image == EGL_NO_IMAGE_KHR) {
// NOTE: if dpy was invalid, createImage() is guaranteed to
// fail. so we'd end up here.
return -EINVAL;
}
}
GLint error;
while ((error = glGetError()) != GL_NO_ERROR) {
ST_LOGW("updateTexImage: clearing GL error: %#04x", error);
}
glBindTexture(mTexTarget, mTexName);
glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
bool failed = false;
while ((error = glGetError()) != GL_NO_ERROR) {
ST_LOGE("error binding external texture image %p (slot %d): %#04x",
image, buf, error);
failed = true;
}
if (failed) {
return -EINVAL;
}
if (mCurrentTexture != INVALID_BUFFER_SLOT) {
// The current buffer becomes FREE if it was still in the queued
// state. If it has already been given to the client
// (synchronous mode), then it stays in DEQUEUED state.
if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED)
mSlots[mCurrentTexture].mBufferState = BufferSlot::FREE;
}
// Update the SurfaceTexture state.
mCurrentTexture = buf;
mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
mCurrentCrop = mSlots[buf].mCrop;
mCurrentTransform = mSlots[buf].mTransform;
mCurrentScalingMode = mSlots[buf].mScalingMode;
mCurrentTimestamp = mSlots[buf].mTimestamp;
computeCurrentTransformMatrix();
// Now that we've passed the point at which failures can happen,
// it's safe to remove the buffer from the front of the queue.
mQueue.erase(front);
mDequeueCondition.signal();
} else {
// We always bind the texture even if we don't update its contents.
glBindTexture(mTexTarget, mTexName);
}
return OK;
}
先说一下这个函数中的 mQueue,这个变量是Vector<int>类型,在 SurfaceTexture::queueBuffer函数中
status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp,
uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
。。。
if (mSynchronousMode) {
// In synchronous mode we queue all buffers in a FIFO.
mQueue.push_back(buf);
// Synchronous mode always signals that an additional frame should
// be consumed.
listener = mFrameAvailableListener;
} else {
// In asynchronous mode we only keep the most recent buffer.
if (mQueue.empty()) {
mQueue.push_back(buf);
// Asynchronous mode only signals that a frame should be
// consumed if no previous frame was pending. If a frame were
// pending then the consumer would have already been notified.
listener = mFrameAvailableListener;
} else {
Fifo::iterator front(mQueue.begin());
// buffer currently queued is freed
mSlots[*front].mBufferState = BufferSlot::FREE;
// and we record the new buffer index in the queued list
*front = buf;
}
}
。。。
}
在同步模式中, queueBuffer把buf 索引放到 mQueue中,表示这是需要处理的 buffer,在异步模式下,由于只需要存储最新的 buffer,所以从mQueue 中取出第一个 buffer的索引,将它对应的buffer的状态设置为 free,然后把新的索引放到队列中去。也就是说,在这种模式下, Queue中只有一个最新的buffer。
在updateTexImage中,判断 mQueue是否为空,也就是说这是一个读写队列,在 Binder线程中通过queueBuffer 把需要处理的 Buffer入队列,在SurfaceFlinger 的主线程中读取 Buffer。updateTexImage 中调用了 createImage函数,它实际上是根据读写队列中 buffer创建了OpenGL|ES 的image,这个 image被保存在相应的slot中。同时,下面两个函数把 image与Tex 绑定起来
glBindTexture(mTexTarget, mTexName);
glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
返回来再看 Layer::lockPageFlip函数,后面的代码就是计算一个 DirtyRegion,即要画image 的那一部分,在 Layer中,也有两个State, DrawingState和CurrentState ,这个State的结构与 SurfaceFlinger的State 结构不同,但是 DrawState同样表示当前已经在屏幕上的状态, CurrentState是当前处理的状态。
3.unlockPageFlip
与lockPageFilp类似,
unlockPageFlip也是编译Z
order layer
,然后调用
layer的unlockPageFilp
函数,该函数并没有做太多的动作,主要就是根据当前
Plane的tranform
对dirtyRegion做一些坐标变换
4.handleRepaint
lockPageFlip实际上是让每个Layer计算出他们的
image,这个函数则是负责把这些
image混合之后画到back
framebuffer上,该函数主要有两个重要的函数
<1>setupHardwareComposer
这里用到了
DisplayHardware中我们没有涉及到的一部分内容,
hwcomposer,这是个硬件模块,用于做图像混合,即
HWComposer类,它在构造函数中加载了
hwcomposer模块,并打开了该设备,得到
hwc_composer_device_t设备,该设备在做comoser的时候使用到了一个重要的结构
hwc_layer_list_t
typedef struct hwc_layer_list {
uint32_t flags;
size_t numHwLayers;
hwc_layer_t hwLayers[0];
} hwc_layer_list_t;
其中hwd_layer_t的结构如下:
typedef struct hwc_layer {
/*
* initially set to HWC_FRAMEBUFFER, indicates the layer will
* be drawn into the framebuffer using OpenGL ES.
* The HWC can toggle this value to HWC_OVERLAY, to indicate
* it will handle the layer.
*/
int32_t compositionType;
uint32_t hints;
uint32_t flags;
/* handle of buffer to compose. this handle is guaranteed to have been
* allocated with gralloc */
buffer_handle_t handle;
uint32_t transform;
int32_t blending;
/* area of the source to consider, the origin is the top-left corner of
* the buffer */
hwc_rect_t sourceCrop;
/* where to composite the sourceCrop onto the display. The sourceCrop
* is scaled using linear filtering to the displayFrame. The origin is the
* top-left corner of the screen.
*/
hwc_rect_t displayFrame;
/* visible region in screen space. The origin is the
* top-left corner of the screen.
* The visible region INCLUDES areas overlapped by a translucent layer.
*/
hwc_region_t visibleRegionScreen;
} hwc_layer_t;
显然, hw_layer_list_t结构中包含了需要进行composer的层信息, hwComposer的prepare 函数就是用于初始化这些层信息的,默认情况下 compositionType是HWC_FRAMEBUFFER 表示使用 OpenGL|ES,硬件设备可以修改它的值为 HWC_OVERLAY,表示由硬件来处理layer, HWComposer类的prepare 方法就是用来初始化 list结构的
setupHardwareComposer函数中比较重要的两点,
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(layers[i]);
layer->setPerFrameData(&cur[i]);
}
这里的 Layer::setPerFrameData函数把Layer 中的handle,即 asm的内存,设置给hwComposer中对应的 hwc_layer_t中的handle
另外,调用了 hwc.prepare函数,用于初始化list结构中的其他部分。经过这两部分设置之后,就可以使用 hwComposer进行compose 了
typedef struct hwc_layer_list {
uint32_t flags;
size_t numHwLayers;
hwc_layer_t hwLayers[0];
} hwc_layer_list_t;
其中hwd_layer_t的结构如下:
typedef struct hwc_layer {
/*
* initially set to HWC_FRAMEBUFFER, indicates the layer will
* be drawn into the framebuffer using OpenGL ES.
* The HWC can toggle this value to HWC_OVERLAY, to indicate
* it will handle the layer.
*/
int32_t compositionType;
uint32_t hints;
uint32_t flags;
/* handle of buffer to compose. this handle is guaranteed to have been
* allocated with gralloc */
buffer_handle_t handle;
uint32_t transform;
int32_t blending;
/* area of the source to consider, the origin is the top-left corner of
* the buffer */
hwc_rect_t sourceCrop;
/* where to composite the sourceCrop onto the display. The sourceCrop
* is scaled using linear filtering to the displayFrame. The origin is the
* top-left corner of the screen.
*/
hwc_rect_t displayFrame;
/* visible region in screen space. The origin is the
* top-left corner of the screen.
* The visible region INCLUDES areas overlapped by a translucent layer.
*/
hwc_region_t visibleRegionScreen;
} hwc_layer_t;
显然, hw_layer_list_t结构中包含了需要进行composer的层信息, hwComposer的prepare 函数就是用于初始化这些层信息的,默认情况下 compositionType是HWC_FRAMEBUFFER 表示使用 OpenGL|ES,硬件设备可以修改它的值为 HWC_OVERLAY,表示由硬件来处理layer, HWComposer类的prepare 方法就是用来初始化 list结构的
setupHardwareComposer函数中比较重要的两点,
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(layers[i]);
layer->setPerFrameData(&cur[i]);
}
这里的 Layer::setPerFrameData函数把Layer 中的handle,即 asm的内存,设置给hwComposer中对应的 hwc_layer_t中的handle
另外,调用了 hwc.prepare函数,用于初始化list结构中的其他部分。经过这两部分设置之后,就可以使用 hwComposer进行compose 了
<2>composeSurfaces
void SurfaceFlinger::composeSurfaces(const Region& dirty)
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
HWComposer& hwc(hw.getHwComposer());
const size_t fbLayerCount = hwc.getLayerCount(HWC_FRAMEBUFFER);
if (UNLIKELY(fbLayerCount && !mWormholeRegion.isEmpty())) {
// should never happen unless the window manager has a bug
// draw something...
drawWormhole();
}
/*
* and then, render the layers targeted at the framebuffer
*/
hwc_layer_t* const cur(hwc.getLayers());
const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
if (cur && (cur[i].compositionType != HWC_FRAMEBUFFER)) {
continue;
}
const sp<LayerBase>& layer(layers[i]);
const Region clip(dirty.intersect(layer->visibleRegionScreen));//这里计算Layer 的可见区域与 drityRegion的clip
if (!clip.isEmpty()) {
layer->draw(clip);//在这个clip 上draw layer
}
}
}
该函数相对也比较简单,关键还是 LayerBase::draw函数,它实际上调用了Layer::onDraw函数,这个函数实际上是调用了众多的 openGL|ES的函数来实现draw的功能,画到 framebuffer上。这里不做过多的说明。在 handleRepaint函数完成之后,接着调用了 DisplayHardware::compositionComplete函数,这个函数调用了frameBufferDevice的 compositionComlete函数,目的就是为了通知 openGL或者硬件composition 操作结束。
{
const DisplayHardware& hw(graphicPlane(0).displayHardware());
HWComposer& hwc(hw.getHwComposer());
const size_t fbLayerCount = hwc.getLayerCount(HWC_FRAMEBUFFER);
if (UNLIKELY(fbLayerCount && !mWormholeRegion.isEmpty())) {
// should never happen unless the window manager has a bug
// draw something...
drawWormhole();
}
/*
* and then, render the layers targeted at the framebuffer
*/
hwc_layer_t* const cur(hwc.getLayers());
const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
if (cur && (cur[i].compositionType != HWC_FRAMEBUFFER)) {
continue;
}
const sp<LayerBase>& layer(layers[i]);
const Region clip(dirty.intersect(layer->visibleRegionScreen));//这里计算Layer 的可见区域与 drityRegion的clip
if (!clip.isEmpty()) {
layer->draw(clip);//在这个clip 上draw layer
}
}
}
该函数相对也比较简单,关键还是 LayerBase::draw函数,它实际上调用了Layer::onDraw函数,这个函数实际上是调用了众多的 openGL|ES的函数来实现draw的功能,画到 framebuffer上。这里不做过多的说明。在 handleRepaint函数完成之后,接着调用了 DisplayHardware::compositionComplete函数,这个函数调用了frameBufferDevice的 compositionComlete函数,目的就是为了通知 openGL或者硬件composition 操作结束。
5.postFramebuffer
该函数调用了
DisplayHardware::flp函数,
void DisplayHardware::flip(const Region& dirty) const
{
checkGLErrors();
EGLDisplay dpy = mDisplay;
EGLSurface surface = mSurface;
#ifdef EGL_ANDROID_swap_rectangle
if (mFlags & SWAP_RECTANGLE) {
const Region newDirty(dirty.intersect(bounds()));
const Rect b(newDirty.getBounds());
eglSetSwapRectangleANDROID(dpy, surface,
b.left, b.top, b.width(), b.height());
}
#endif
if (mFlags & PARTIAL_UPDATES) {
mNativeWindow->setUpdateRectangle(dirty.getBounds());
}
mPageFlipCount++;
if (mHwc->initCheck() == NO_ERROR) {
mHwc->commit();//如果hwComposer 已经初始化就调用它的 commit函数把内容画到屏幕上去
} else {
eglSwapBuffers(dpy, surface);//让openGL|ES 使用framebuffer把内容写到屏幕设备上去, eglSwapBuffer在前面已经分析过
}
checkEGLErrors("eglSwapBuffers");
// for debugging
//glClearColor(1,0,0,0);
//glClear(GL_COLOR_BUFFER_BIT);
}
void DisplayHardware::flip(const Region& dirty) const
{
checkGLErrors();
EGLDisplay dpy = mDisplay;
EGLSurface surface = mSurface;
#ifdef EGL_ANDROID_swap_rectangle
if (mFlags & SWAP_RECTANGLE) {
const Region newDirty(dirty.intersect(bounds()));
const Rect b(newDirty.getBounds());
eglSetSwapRectangleANDROID(dpy, surface,
b.left, b.top, b.width(), b.height());
}
#endif
if (mFlags & PARTIAL_UPDATES) {
mNativeWindow->setUpdateRectangle(dirty.getBounds());
}
mPageFlipCount++;
if (mHwc->initCheck() == NO_ERROR) {
mHwc->commit();//如果hwComposer 已经初始化就调用它的 commit函数把内容画到屏幕上去
} else {
eglSwapBuffers(dpy, surface);//让openGL|ES 使用framebuffer把内容写到屏幕设备上去, eglSwapBuffer在前面已经分析过
}
checkEGLErrors("eglSwapBuffers");
// for debugging
//glClearColor(1,0,0,0);
//glClear(GL_COLOR_BUFFER_BIT);
}
6.handleTransaction
这一部分在
Surface中有详细说明