SF中的工作線程就是來做圖像混合的,比起AudioFlinger來,它相當簡單,下面是它的代碼:
**SurfaceFlinger.cpp**
~~~
bool SurfaceFlinger::threadLoop()
{
waitForEvent();//① 等待什么事件呢?
if (UNLIKELY(mConsoleSignals)) {
handleConsoleEvents();
}
if(LIKELY(mTransactionCount == 0)) {
const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
uint32_t transactionFlags = getTransactionFlags(mask);
if(LIKELY(transactionFlags)) {
//Transaction(事務)處理,放到本節最后來討論
handleTransaction(transactionFlags);
}
}
//②處理PageFlipping工作
handlePageFlip();
constDisplayHardware& hw(graphicPlane(0).displayHardware());
if (LIKELY(hw.canDraw() && !isFrozen())) {
//③處理重繪
handleRepaint();
hw.compositionComplete();
//④投遞BackBuffer
unlockClients();
postFramebuffer();
} else{
unlockClients();
usleep(16667);
}
returntrue;
}
~~~
ThreadLoop一共有四個關鍵點,這里,分析除Transaction外的三個關鍵點。
1. waitForEvent
SF工作線程一上來就等待事件,它會是什么事件呢?來看代碼:
**SurfaceFlinger.cpp**
~~~
void SurfaceFlinger::waitForEvent()
{
while(true) {
nsecs_t timeout = -1;
const nsecs_t freezeDisplayTimeout = ms2ns(5000);
......
MessageList::value_type msg = mEventQueue.waitMessage(timeout);
......//還有一些和凍屏相關的內容
if(msg != 0) {
switch (msg->what) {
//千辛萬苦就等這一個重繪消息
case MessageQueue::INVALIDATE:
return;
}
}
}
}
~~~
SF收到重繪消息后,將退出等待。那么,是誰發送的這個重繪消息呢?還記得在unlockCanvasAndPost函數中調用的signal嗎?它在SF端的實現代碼如下:
**SurfaceFlinger**
~~~
void SurfaceFlinger::signal() const {
const_cast<SurfaceFlinger*>(this)->signalEvent();
}
void SurfaceFlinger::signalEvent() {
mEventQueue.invalidate(); //往消息隊列中加入INVALIDATE消息
}
~~~
2. 分析handlePageFlip
SF工作線程從waitForEvent中返回后,下一步要做的就是處理事務和handlePageFlip了。先看handlePageFlip,從名字上可知,它和PageFlipping工作有關。
* * * * *
**注意**:事務處理將在8.5.3節中介紹。
* * * * *
代碼如下所示:
**SurfaceFlinger.cpp**
~~~
void SurfaceFlinger::handlePageFlip()
{
bool visibleRegions = mVisibleRegionsDirty;
/*
還記得前面所說的mCurrentState嗎?它保存了所有顯示層的信息,而繪制的時候使用的
mDrawingState則保存了當前需要顯示的顯示層信息。
*/
LayerVector& currentLayers =
const_cast<LayerVector&>(mDrawingState.layersSortedByZ);
//①調用lockPageFlip
visibleRegions |= lockPageFlip(currentLayers);
const DisplayHardware& hw =graphicPlane(0).displayHardware();
//取得屏幕的區域
const Region screenRegion(hw.bounds());
if (visibleRegions) {
Region opaqueRegion;
computeVisibleRegions(currentLayers, mDirtyRegion,opaqueRegion);
mWormholeRegion = screenRegion.subtract(opaqueRegion);
mVisibleRegionsDirty = false;
}
//② 調用unlockPageFlip
unlockPageFlip(currentLayers);
mDirtyRegion.andSelf(screenRegion);
}
~~~
hanldePageFlip調用了兩個看起來是一對的函數:lockPageFlip和unlockPageFlip。這兩個函數會干些什么呢?
(1)lockPageFlip的分析
先看lockPageFlip函數,代碼如下所示:
**SurfaceFlinger.cpp**
~~~
bool SurfaceFlinger::lockPageFlip(constLayerVector& currentLayers)
{
boolrecomputeVisibleRegions = false;
size_tcount = currentLayers.size();
sp<LayerBase> const* layers = currentLayers.array();
for(size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer = layers[i];
//調用每個顯示層的lockPageFlip
layer->lockPageFlip(recomputeVisibleRegions);
}
returnrecomputeVisibleRegions;
}
~~~
假設當前的顯示層是Layer類型,那么得轉到Layer類去看它的lockPageFlip函數,代碼如下所示:
**Layer.cpp**
~~~
void Layer::lockPageFlip(bool&recomputeVisibleRegions)
{
//lcblk是SharedBufferServer類型,調用retireAndLock函數將返回FrontBuffer的
//索引號
ssize_tbuf = lcblk->retireAndLock();
......
mFrontBufferIndex = buf;
//得到FrontBuffer對應的GraphicBuffer
sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
if (newFrontBuffer != NULL) {
//取出臟區域
const Region dirty(lcblk->getDirtyRegion(buf));
//和GraphicBuffer所表示的區域進行裁剪,得到一個臟區域
mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() );
const Layer::State& front(drawingState());
if(newFrontBuffer->getWidth() ==front.requested_w &&
newFrontBuffer->getHeight() ==front.requested_h)
{
if ((front.w != front.requested_w) ||
(front.h != front.requested_h))
{
...... //需要重新計算可見區域
recomputeVisibleRegions = true;
}
mFreezeLock.clear();
}
} else{
mPostedDirtyRegion.clear();
}
if(lcblk->getQueuedCount()) {
mFlinger->signalEvent();
}
/*
如果臟區域不為空,則需要繪制成紋理,reloadTexture將繪制一張紋理保存在
mTextures數組中,里邊涉及很多OpenGL的操作,讀者有興趣可以自己研究。
*/
if(!mPostedDirtyRegion.isEmpty()) {
reloadTexture( mPostedDirtyRegion );
}
}
~~~
我們知道,Layer的lockPageFlip將根據FrontBuffer的內容生成一張紋理。那么,unlockPageFlip會做些什么呢?
(2)unlockPageFlip的分析
unlockPageFlip的代碼如下所示:
**SurfaceFlinger.cpp**
~~~
void SurfaceFlinger::unlockPageFlip(constLayerVector& currentLayers)
{
constGraphicPlane& plane(graphicPlane(0));
constTransform& planeTransform(plane.transform());
size_tcount = currentLayers.size();
sp<LayerBase> const* layers = currentLayers.array();
for(size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer = layers[i];
//調用每個顯示層的unlockPageFlip,Layer的unlockPageFlip主要做一些
//區域的清理工作,讀者可以自己看看。
layer->unlockPageFlip(planeTransform, mDirtyRegion);
}
}
~~~
(3)handlePageFlip的總結
handlePageFlip的工作其實很簡單,以Layer類型為例來總結一下:
各個Layer需要從FrontBuffer中取得新數據,并生成一張OpenGL中的紋理。紋理可以看做是一個圖片,這個圖片的內容就是FrontBuffer中的圖像。
現在每一個Layer都準備好了新數據,下一步的工作當然就是繪制了。來看handleRepaint函數。
3. 分析handleRepaint函數
handleRepaint函數的代碼如下所示:
**SurfaceFlinger.cpp**
~~~
void SurfaceFlinger::handleRepaint()
{
mInvalidRegion.orSelf(mDirtyRegion);
if(mInvalidRegion.isEmpty()) {
return;
}
......
constDisplayHardware& hw(graphicPlane(0).displayHardware());
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
uint32_t flags = hw.getFlags();
if((flags & DisplayHardware::SWAP_RECTANGLE) ||
(flags & DisplayHardware::BUFFER_PRESERVED))
{
......//計算mDirtyRegion
}
// 在臟區域上進行繪制
composeSurfaces(mDirtyRegion);
mDirtyRegion.clear();
}
~~~
其中,composeSurfaces將不同的顯示層內容進行混合,其實就是按Z軸的順序由里到外依次繪制。當然,最后繪制的數據有可能遮蓋前面繪制的數據,代碼如下所示:
**SurfaceFlinger.cpp**
~~~
void SurfaceFlinger::composeSurfaces(constRegion& dirty)
{
constSurfaceFlinger& flinger(*this);
constLayerVector& drawingLayers(mDrawingState.layersSortedByZ);
constsize_t count = drawingLayers.size();
sp<LayerBase> const* const layers = drawingLayers.array();
for(size_t i=0 ; i<count ; ++i) {
const sp<LayerBase>& layer = layers[i];
const Region&visibleRegion(layer->visibleRegionScreen);
if(!visibleRegion.isEmpty()) {
const Region clip(dirty.intersect(visibleRegion));
if (!clip.isEmpty()) {
layer->draw(clip); //調用各個顯示層的layer函數
}
}
}
}
~~~
draw函數在LayerBase類中實現,代碼如下所示:
**LayerBase.cpp**
~~~
void LayerBase::draw(const Region& inClip)const
{
......
glEnable(GL_SCISSOR_TEST);
onDraw(clip);//調用子類的onDraw函數
}
~~~
至于Layer是怎么實現這個onDraw函數的,代碼如下所示:
**Layer.cpp**
~~~
void Layer::onDraw(const Region& clip) const
{
intindex = mFrontBufferIndex;
if(mTextures[index].image == EGL_NO_IMAGE_KHR)
index = 0;
GLuint textureName = mTextures[index].name;
....
Region holes(clip.subtract(under));
if(!holes.isEmpty()) {
clearWithOpenGL(holes);
}
return;
}
//index是FrontBuffer對應生成的紋理,在lockPageFlip函數中就已經生成了。
drawWithOpenGL(clip,mTextures[index]);//將紋理畫上去,里面有很多和OpenGL相關內容
}
~~~
drawWithOpenGL函數由LayerBase實現,看它是不是使用了這張紋理,代碼如下所示:
**LayerBase.cpp**
~~~
void LayerBase::drawWithOpenGL(const Region&clip, const Texture& texture) const
{
constDisplayHardware& hw(graphicPlane(0).displayHardware());
constuint32_t fbHeight = hw.getHeight();
constState& s(drawingState());
//validateTexture函數內部將綁定指定的紋理
validateTexture(texture.name);
//下面就是OpenGL操作函數了
glEnable(GL_TEXTURE_2D);
......
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
//坐標旋轉
switch(texture.transform) {
case HAL_TRANSFORM_ROT_90:
glTranslatef(0, 1, 0);
glRotatef(-90, 0, 0, 1);
break;
case HAL_TRANSFORM_ROT_180:
glTranslatef(1, 1, 0);
glRotatef(-180, 0, 0, 1);
break;
case HAL_TRANSFORM_ROT_270:
glTranslatef(1, 0, 0);
glRotatef(-270, 0, 0, 1);
break;
}
if (texture.NPOTAdjust) {
//縮放處理
glScalef(texture.wScale, texture.hScale, 1.0f);
}
//使能紋理坐標
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//設置頂點坐標
glVertexPointer(2, GL_FIXED, 0, mVertices);
//設置紋理坐標
glTexCoordPointer(2, GL_FIXED, 0, texCoords);
while(it != end) {
const Rect& r = *it++;
const GLint sy = fbHeight - (r.top + r.height());
//裁剪
glScissor(r.left, sy, r.width(), r.height());
//畫矩形
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
//禁止紋理坐標
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
~~~
紋理綁定是OpenGL的常用函數,其代碼如下所示。
**LayerBase.cpp**
~~~
void LayerBase::validateTexture(GLinttextureName) const
{
//下面這個函數將綁定紋理
glBindTexture(GL_TEXTURE_2D, textureName);
......//其他一些設置
}
~~~
handleRepaint這個函數基本上就是按Z軸的順序對每一層進行重繪,重繪的方法就是使用OpenGL。
我在Android平臺上有幾個月的OpenGL開發經歷,還談不上很深刻,其中的一些資料,希望能夠給感興趣的讀者提供參考。
1)OpenGL的入門教材當選NeHe的資料,大略看前幾章即可。
2) Android平臺上關于OpenGL ES的開發,有一篇很詳細的Word文檔叫《OpenGL ESTutorial for Android》。該文詳細描述了在Android平臺上進行OpenGL開發的流程。大家可跟著這篇教材,在模擬器上做一些練習。那里面涉及到的一些基礎知識,從前面介紹的入門教材中可以學到。
3)有了前面兩點的基礎后,就需要對整個OpenGL有比較完整深入的了解了。我在那時所看的書是《OpenGL Programming Guide (7th Edition)》。該書很厚,有1000多頁。里面有一些內容可能與工作無涉,只要大概知道有那回事就行了,暫時不必深入學習,等需要時再進一步學習并運用。我在開發的項目中曾用到的光照、霧化等效果,都是之前先知道有這個東西,后來在項目中才逐漸學習運用的。
4)嵌入式平臺上用的其實是OpenGL ES。這里,還有一本書叫《OpenGL ES 2.0 Programming Guide》,它介紹了OpenGL ES的開發,讀者可認真修習。
5)在Android SDK文檔中,對OpenGL API的描述只寥寥數語。怎么辦?由于它使用了J2ME中的javax.microedition.khronos.opengles包,所以J2ME的SDK文檔中對OpenGL的API有著非常詳細的描述,讀者手頭應該要有一個J2ME的文檔。
6)如果想做深入開發,就不得不學習計算機圖形學了。我后來買了書,可惜沒時間學了。
4. unlockClients和postFrameBuffer的分析
在繪制完圖后,還有兩項工作需要做,一個涉及unlockClients函數,另外一個涉及postFrameBuffer函數,這兩個函數分別干了什么呢?unlockClients的代碼如下所示:
**SurfaceFlinger.cpp**
~~~
void SurfaceFlinger::unlockClients()
{
constLayerVector& drawingLayers(mDrawingState.layersSortedByZ);
constsize_t count = drawingLayers.size();
sp<LayerBase> const* const layers = drawingLayers.array();
for (size_t i=0 ; i<count ; ++i) {
const sp<LayerBase>& layer = layers[i];
layer->finishPageFlip();
}
}
~~~
再看Layer的finishPageFlip函數,代碼如下所示:
**Layer.cpp**
~~~
void Layer::finishPageFlip()
{
//釋放FrontBufferIndex
status_t err = lcblk->unlock( mFrontBufferIndex );
}
~~~
原來,unlockClients會釋放之前占著的FrontBuffer的索引號。下面看最后一個函數postFrameBuffer,代碼如下所示:
**SurfaceFlinger.cpp**
~~~
void SurfaceFlinger::postFramebuffer()
{
if(!mInvalidRegion.isEmpty()) {
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const nsecs_t now = systemTime();
mDebugInSwapBuffers = now;
//調用這個函數后,混合后的圖像就會傳遞到屏幕中顯示了
hw.flip(mInvalidRegion);
mLastSwapBufferTime = systemTime() - now;
mDebugInSwapBuffers = 0;
mInvalidRegion.clear();
}
}
~~~
flip將調用在DisplayHardware一節中提到的eglSwapBuffer函數,來完成FrameBuffer的PageFlip操作,代碼如下所示:
**DisplayHardware.cpp**
~~~
void DisplayHardware::flip(const Region&dirty) const
{
checkGLErrors();
EGLDisplay dpy = mDisplay;
EGLSurface surface = mSurface;
......
if(mFlags & PARTIAL_UPDATES) {
mNativeWindow->setUpdateRectangle(dirty.getBounds());
}
mPageFlipCount++;
eglSwapBuffers(dpy, surface);//PageFlipping,此后圖像終于顯示在屏幕上了!
}
~~~
- 前言
- 第1章 閱讀前的準備工作
- 1.1 系統架構
- 1.1.1 Android系統架構
- 1.1.2 本書的架構
- 1.2 搭建開發環境
- 1.2.1 下載源碼
- 1.2.2 編譯源碼
- 1.3 工具介紹
- 1.3.1 Source Insight介紹
- 1.3.2 Busybox的使用
- 1.4 本章小結
- 第2章 深入理解JNI
- 2.1 JNI概述
- 2.2 學習JNI的實例:MediaScanner
- 2.3 Java層的MediaScanner分析
- 2.3.1 加載JNI庫
- 2.3.2 Java的native函數和總結
- 2.4 JNI層MediaScanner的分析
- 2.4.1 注冊JNI函數
- 2.4.2 數據類型轉換
- 2.4.3 JNIEnv介紹
- 2.4.4 通過JNIEnv操作jobject
- 2.4.5 jstring介紹
- 2.4.6 JNI類型簽名介紹
- 2.4.7 垃圾回收
- 2.4.8 JNI中的異常處理
- 2.5 本章小結
- 第3章 深入理解init
- 3.1 概述
- 3.2 init分析
- 3.2.1 解析配置文件
- 3.2.2 解析service
- 3.2.3 init控制service
- 3.2.4 屬性服務
- 3.3 本章小結
- 第4章 深入理解zygote
- 4.1 概述
- 4.2 zygote分析
- 4.2.1 AppRuntime分析
- 4.2.2 Welcome to Java World
- 4.2.3 關于zygote的總結
- 4.3 SystemServer分析
- 4.3.1 SystemServer的誕生
- 4.3.2 SystemServer的重要使命
- 4.3.3 關于 SystemServer的總結
- 4.4 zygote的分裂
- 4.4.1 ActivityManagerService發送請求
- 4.4.2 有求必應之響應請求
- 4.4.3 關于zygote分裂的總結
- 4.5 拓展思考
- 4.5.1 虛擬機heapsize的限制
- 4.5.2 開機速度優化
- 4.5.3 Watchdog分析
- 4.6 本章小結
- 第5章 深入理解常見類
- 5.1 概述
- 5.2 以“三板斧”揭秘RefBase、sp和wp
- 5.2.1 第一板斧--初識影子對象
- 5.2.2 第二板斧--由弱生強
- 5.2.3 第三板斧--破解生死魔咒
- 5.2.4 輕量級的引用計數控制類LightRefBase
- 5.2.5 題外話-三板斧的來歷
- 5.3 Thread類及常用同步類分析
- 5.3.1 一個變量引發的思考
- 5.3.2 常用同步類
- 5.4 Looper和Handler類分析
- 5.4.1 Looper類分析
- 5.4.2 Handler分析
- 5.4.3 Looper和Handler的同步關系
- 5.4.4 HandlerThread介紹
- 5.5 本章小結
- 第6章 深入理解Binder
- 6.1 概述
- 6.2 庖丁解MediaServer
- 6.2.1 MediaServer的入口函數
- 6.2.2 獨一無二的ProcessState
- 6.2.3 時空穿越魔術-defaultServiceManager
- 6.2.4 注冊MediaPlayerService
- 6.2.5 秋風掃落葉-StartThread Pool和join Thread Pool分析
- 6.2.6 你徹底明白了嗎
- 6.3 服務總管ServiceManager
- 6.3.1 ServiceManager的原理
- 6.3.2 服務的注冊
- 6.3.3 ServiceManager存在的意義
- 6.4 MediaPlayerService和它的Client
- 6.4.1 查詢ServiceManager
- 6.4.2 子承父業
- 6.5 拓展思考
- 6.5.1 Binder和線程的關系
- 6.5.2 有人情味的訃告
- 6.5.3 匿名Service
- 6.6 學以致用
- 6.6.1 純Native的Service
- 6.6.2 扶得起的“阿斗”(aidl)
- 6.7 本章小結
- 第7章 深入理解Audio系統
- 7.1 概述
- 7.2 AudioTrack的破解
- 7.2.1 用例介紹
- 7.2.2 AudioTrack(Java空間)分析
- 7.2.3 AudioTrack(Native空間)分析
- 7.2.4 關于AudioTrack的總結
- 7.3 AudioFlinger的破解
- 7.3.1 AudioFlinger的誕生
- 7.3.2 通過流程分析AudioFlinger
- 7.3.3 audio_track_cblk_t分析
- 7.3.4 關于AudioFlinger的總結
- 7.4 AudioPolicyService的破解
- 7.4.1 AudioPolicyService的創建
- 7.4.2 重回AudioTrack
- 7.4.3 聲音路由切換實例分析
- 7.4.4 關于AudioPolicy的總結
- 7.5 拓展思考
- 7.5.1 DuplicatingThread破解
- 7.5.2 題外話
- 7.6 本章小結
- 第8章 深入理解Surface系統
- 8.1 概述
- 8.2 一個Activity的顯示
- 8.2.1 Activity的創建
- 8.2.2 Activity的UI繪制
- 8.2.3 關于Activity的總結
- 8.3 初識Surface
- 8.3.1 和Surface有關的流程總結
- 8.3.2 Surface之乾坤大挪移
- 8.3.3 乾坤大挪移的JNI層分析
- 8.3.4 Surface和畫圖
- 8.3.5 初識Surface小結
- 8.4 深入分析Surface
- 8.4.1 與Surface相關的基礎知識介紹
- 8.4.2 SurfaceComposerClient分析
- 8.4.3 SurfaceControl分析
- 8.4.4 writeToParcel和Surface對象的創建
- 8.4.5 lockCanvas和unlockCanvasAndPost分析
- 8.4.6 GraphicBuffer介紹
- 8.4.7 深入分析Surface的總結
- 8.5 SurfaceFlinger分析
- 8.5.1 SurfaceFlinger的誕生
- 8.5.2 SF工作線程分析
- 8.5.3 Transaction分析
- 8.5.4 關于SurfaceFlinger的總結
- 8.6 拓展思考
- 8.6.1 Surface系統的CB對象分析
- 8.6.2 ViewRoot的你問我答
- 8.6.3 LayerBuffer分析
- 8.7 本章小結
- 第9章 深入理解Vold和Rild
- 9.1 概述
- 9.2 Vold的原理與機制分析
- 9.2.1 Netlink和Uevent介紹
- 9.2.2 初識Vold
- 9.2.3 NetlinkManager模塊分析
- 9.2.4 VolumeManager模塊分析
- 9.2.5 CommandListener模塊分析
- 9.2.6 Vold實例分析
- 9.2.7 關于Vold的總結
- 9.3 Rild的原理與機制分析
- 9.3.1 初識Rild
- 9.3.2 RIL_startEventLoop分析
- 9.3.3 RIL_Init分析
- 9.3.4 RIL_register分析
- 9.3.5 關于Rild main函數的總結
- 9.3.6 Rild實例分析
- 9.3.7 關于Rild的總結
- 9.4 拓展思考
- 9.4.1 嵌入式系統的存儲知識介紹
- 9.4.2 Rild和Phone的改進探討
- 9.5 本章小結
- 第10章 深入理解MediaScanner
- 10.1 概述
- 10.2 android.process.media分析
- 10.2.1 MSR模塊分析
- 10.2.2 MSS模塊分析
- 10.2.3 android.process.media媒體掃描工作的流程總結
- 10.3 MediaScanner分析
- 10.3.1 Java層分析
- 10.3.2 JNI層分析
- 10.3.3 PVMediaScanner分析
- 10.3.4 關于MediaScanner的總結
- 10.4 拓展思考
- 10.4.1 MediaScannerConnection介紹
- 10.4.2 我問你答
- 10.5 本章小結