Android — SurfaceFlinger 合成主線程 系列 (三)

來源:互聯網
上載者:User

SurfaceFlinger 屬於system_server進程,在system_init.cpp中利用SurfaceFlinger::instantiate()啟動,在此加入到service manager中,所以本身提供service服務功能。


首先看下SurfaceFlinger的類聲明:

class SurfaceFlinger :
        public BinderService<SurfaceFlinger>,
        public BnSurfaceComposer,
        protected Thread


從介面可以看出使用Binder與用戶端通訊,並且繼承線程 Thread 類,則迴圈執行threadLoop。完成系統中的各個Layer-Surface進行混合,然後將一幀幀混合好的映像傳送到顯示framebuffer中。

其主線程工作流程圖如下:




下面就這以五步將代碼一一過一遍:
1、waitForEvent() 等待什麼事情呢?


void SurfaceFlinger::waitForEvent()
{
    while (true) {
     ......
    
       sp<MessageBase> msg = mEventQueue.waitMessage(timeout);
     ......
        if (msg != 0) {
            switch (msg->what) {
             //等的就是這個訊息事件喲。。。。
                case MessageQueue::INVALIDATE:
                    // invalidate message, just return to the main loop
                    return;
            }
        }    
  }
}


原來是等待收到MessageQueue::INVALIDATE重繪訊息才退回到主線程,那麼這個訊息由誰來發送呢?

請看下面代碼:
void SurfaceFlinger::signalEvent() {
    mEventQueue.invalidate();
}

void SurfaceFlinger::signal() const {
    // this is the IPC call
    const_cast<SurfaceFlinger*>(this)->signalEvent();
}


這是就是發送訊息的點,這個函數signalEvent由誰來調用呢?其個這個發起都是上一節說的,在釋放Surface對應的顯示緩衝區需要顯示時調用:
unlockAndPost() --> queueBuffer() --> mClient.signalServer() --> SurfaceFlinger::signal()


2、handlePageFlip()  
該階段會遍曆各個Layer,在每個Layer中,取得並鎖住該Layer的frontBuffer,然後利用frontBuffer 中的映像資料產生該Layer的2D貼圖(Texture),並且計算更新地區,為後續的混合操作做準備。


void SurfaceFlinger::handlePageFlip()
{
//調用 lockPageFlip
visibleRegions |= lockPageFlip(currentLayers);

//取得螢幕的地區
const Region screenRegion(hw.bounds());
if (visibleRegions) {
   Region opaqueRegion;
   computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);
   .....
   mWormholeRegion = screenRegion.subtract(opaqueRegion);
}
.....
//調用 unlockPageFlip
unlockPageFlip(currentLayers);
}

上面的調用實際上是一對函數:lockPageFlip & lockPageFlip,那麼主要幹些啥呢?

bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers)
{
    bool recomputeVisibleRegions = false;
    size_t count = currentLayers.size();
    sp<LayerBase> const* layers = currentLayers.array();

    //逐個 layer 進行處理 
    for (size_t i=0 ; i<count ; i++) {
        const sp<LayerBase>& layer(layers[i]);
        layer->lockPageFlip(recomputeVisibleRegions);
    }
    return recomputeVisibleRegions;
}

void Layer::lockPageFlip(bool& recomputeVisibleRegions)
{
SharedBufferServer* lcblk(sharedClient.get());

// 擷取當前可用的 frontbuffer 索引號
ssize_t buf = lcblk->retireAndLock();

// 計算當前的髒地區
  sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
  if (newFrontBuffer != NULL) {
      // get the dirty region
      // compute the posted region
      const Region dirty(lcblk->getDirtyRegion(buf));
      mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() );
      ....

// 如果有髒地區需要重繪,則產生 OpenGL ES 紋理貼圖
reloadTexture( mPostedDirtyRegion );
}

void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers)
{
    const GraphicPlane& plane(graphicPlane(0));
    const Transform& planeTransform(plane.transform());
    size_t count = currentLayers.size();
    sp<LayerBase> const* layers = currentLayers.array();
    for (size_t i=0 ; i<count ; i++) {
        const sp<LayerBase>& layer(layers[i]);

//進列區域的清理工作
        layer->unlockPageFlip(planeTransform, mDirtyRegion);
    }
}

void Layer::unlockPageFlip(
        const Transform& planeTransform, Region& outDirtyRegion)
{
    Region dirtyRegion(mPostedDirtyRegion);
    if (!dirtyRegion.isEmpty()) {
        mPostedDirtyRegion.clear();
....
    if (visibleRegionScreen.isEmpty()) {
        // an invisible layer should not hold a freeze-lock
        // (because it may never be updated and therefore never release it)
        mFreezeLock.clear();
    }
}


以上的工作就是按照 Zorder 序計算自已螢幕上的可顯示地區:
1、以自己的W,H給出自己初始的可見地區
2、減去自己上面視窗所覆蓋的地區





3、handleRepaint
每個Layer的資料都準備好了,並且各個髒地區也計算ok,下步就是根據 Zorder 序從底部將資料繪製到主Surface上


void SurfaceFlinger::handleRepaint()
{
    // compute the invalid region
    mInvalidRegion.orSelf(mDirtyRegion);

....

    // compose all surfaces
    composeSurfaces(mDirtyRegion);

    // clear the dirty regions
    mDirtyRegion.clear();
}

void SurfaceFlinger::composeSurfaces(const Region& dirty)
{
...
    const size_t count = layers.size();
    for (size_t i=0 ; i<count ; ++i) {
        const sp<LayerBase>& layer(layers[i]);
        const Region clip(dirty.intersect(layer->visibleRegionScreen));
        if (!clip.isEmpty()) {
            // 這就是繪圖核心函數
            layer->draw(clip);
        }
    }
}

void Layer::onDraw(const Region& clip) const
---> drawWithOpenGL(clip, tex); 基本上都是OpenGL ES 操作函數

    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);
    }

4、unlockClients()
釋放 handlePageFlip 佔用的 frontbuffer 索引號,以便用戶端可以繼續在新的surface畫圖


void SurfaceFlinger::unlockClients()
{
...
    for (size_t i=0 ; i<count ; ++i) {
        const sp<LayerBase>& layer = layers[i];
        layer->finishPageFlip();
    }
}

-->
SharedBufferServer* lcblk(sharedClient.get());
status_t err = lcblk->unlock( buf );

5、postFramebuffer()
現在已經將所有的Layer圖層資料合成完成,最後就是輸入到螢幕上顯示了


void SurfaceFlinger::postFramebuffer()
{
//調用此函數將混合後的映像傳遞到螢幕中進行顯示
hw.flip(mInvalidRegion);
...
}

void DisplayHardware::flip(const Region& dirty) const
{
// 顯示映像吧。。。。。
    eglSwapBuffers(dpy, surface);

}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.