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
中有详细说明