Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> android Gui系統之SurfaceFlinger(4),androidgui系統

android Gui系統之SurfaceFlinger(4),androidgui系統

編輯:關於android開發

android Gui系統之SurfaceFlinger(4),androidgui系統


8.Vsync

8.1概論

VSYNC(Vertical Synchronization)是一個相當古老的概念,對於游戲玩家,它有一個更加大名鼎鼎的中文名字—-垂直同步。

“垂直同步(vsync)”指的是顯卡的輸出幀數和屏幕的垂直刷新率相同,這完全是一個CRT顯示器上的概念。其實無論是VSYNC還是垂直同步這個名字,

因為LCD根本就沒有垂直掃描的這種東西,因此這個名字本身已經沒有意義。但是基於歷史的原因,這個名稱在圖形圖像領域被沿襲下來。
在當下,垂直同步的含義我們可以理解為,使得顯卡生成幀的速度和屏幕刷新的速度的保持一致。舉例來說,如果屏幕的刷新率為60Hz,那麼生成幀

的速度就應該被固定在1/60 s。

8.2 VSync信號的產生和分發

VSync信號的產生在android_frameworks_native\services\surfaceflinger\DisplayHardware\HWComposer.cpp裡面定義:

HWComposer::HWComposer( const sp<SurfaceFlinger>& flinger, EventHandler& handler) : mFlinger(flinger), mFbDev(0), mHwc(0), mNumDisplays(1), mCBContext(new cb_context), mEventHandler(handler), mDebugForceFakeVSync(false), mVDSEnabled(false) { for (size_t i =0 ; i<MAX_HWC_DISPLAYS ; i++) { mLists[i] = 0; } for (size_t i=0 ; i<HWC_NUM_PHYSICAL_DISPLAY_TYPES ; i++) { mLastHwVSync[i] = 0; mVSyncCounts[i] = 0; } char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.no_hw_vsync", value, "0"); mDebugForceFakeVSync = atoi(value); bool needVSyncThread = true; // Note: some devices may insist that the FB HAL be opened before HWC. int fberr = loadFbHalModule(); loadHwcModule(); if (mFbDev && mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { // close FB HAL if we don't needed it. // FIXME: this is temporary until we're not forced to open FB HAL // before HWC. framebuffer_close(mFbDev); mFbDev = NULL; } // If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory. if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) && !mFbDev) { ALOGE("ERROR: failed to open framebuffer (%s), aborting", strerror(-fberr)); abort(); } // these display IDs are always reserved for (size_t i=0 ; i<NUM_BUILTIN_DISPLAYS ; i++) { mAllocatedDisplayIDs.markBit(i); } if (mHwc) { ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER, (hwcApiVersion(mHwc) >> 24) & 0xff, (hwcApiVersion(mHwc) >> 16) & 0xff); if (mHwc->registerProcs) { mCBContext->hwc = this; mCBContext->procs.invalidate = &hook_invalidate; mCBContext->procs.vsync = &hook_vsync; if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) mCBContext->procs.hotplug = &hook_hotplug; else mCBContext->procs.hotplug = NULL; memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero)); mHwc->registerProcs(mHwc, &mCBContext->procs); } // don't need a vsync thread if we have a hardware composer needVSyncThread = false; // always turn vsync off when we start eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0); // the number of displays we actually have depends on the // hw composer version if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { // 1.3 adds support for virtual displays mNumDisplays = MAX_HWC_DISPLAYS; } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { // 1.1 adds support for multiple displays mNumDisplays = NUM_BUILTIN_DISPLAYS; } else { mNumDisplays = 1; } } if (mFbDev) { ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)), "should only have fbdev if no hwc or hwc is 1.0"); DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]); disp.connected = true; disp.format = mFbDev->format; DisplayConfig config = DisplayConfig(); config.width = mFbDev->width; config.height = mFbDev->height; config.xdpi = mFbDev->xdpi; config.ydpi = mFbDev->ydpi; #ifdef QCOM_BSP config.secure = true; //XXX: Assuming primary is always true #endif config.refresh = nsecs_t(1e9 / mFbDev->fps); disp.configs.push_back(config); disp.currentConfig = 0; } else if (mHwc) { // here we're guaranteed to have at least HWC 1.1 for (size_t i =0 ; i<NUM_BUILTIN_DISPLAYS ; i++) { queryDisplayProperties(i); } } // read system property for VDS solution // This property is expected to be setup once during bootup if( (property_get("persist.hwc.enable_vds", value, NULL) > 0) && ((!strncmp(value, "1", strlen("1"))) || !strncasecmp(value, "true", strlen("true")))) { //HAL virtual display is using VDS based implementation mVDSEnabled = true; } if (needVSyncThread) { // we don't have VSYNC support, we need to fake it mVSyncThread = new VSyncThread(*this); } #ifdef QCOM_BSP // Threshold Area to enable GPU Tiled Rect. property_get("debug.hwc.gpuTiledThreshold", value, "1.9"); mDynThreshold = atof(value); #endif } HWComposer
bool needVSyncThread = true;

是否需要模擬產生VSync信號,默認是開啟的。

  // Note: some devices may insist that the FB HAL be opened before HWC.
    int fberr = loadFbHalModule();
    loadHwcModule();

打開fb & hwc設備的HAL模塊。

        if (mHwc->registerProcs) {
            mCBContext->hwc = this;
            mCBContext->procs.invalidate = &hook_invalidate;
            mCBContext->procs.vsync = &hook_vsync;
            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
                mCBContext->procs.hotplug = &hook_hotplug;
            else
                mCBContext->procs.hotplug = NULL;
            memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
            mHwc->registerProcs(mHwc, &mCBContext->procs);
        }

        // don't need a vsync thread if we have a hardware composer
        needVSyncThread = false;

硬件VSync信號啟動,不需要軟件模擬。

    if (needVSyncThread) {
        // we don't have VSYNC support, we need to fake it
        mVSyncThread = new VSyncThread(*this);
    }

如果需要,啟動VSyncThread線程來開啟軟件模擬。

8.2.1硬件產生

mHwc->registerProcs(mHwc, &mCBContext->procs);

hwc會產生回調:procs.vsync & procs.invalidate 信號。

void HWComposer::vsync(int disp, int64_t timestamp) {
    if (uint32_t(disp) < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
        {
            Mutex::Autolock _l(mLock);

            // There have been reports of HWCs that signal several vsync events
            // with the same timestamp when turning the display off and on. This
            // is a bug in the HWC implementation, but filter the extra events
            // out here so they don't cause havoc downstream.
            if (timestamp == mLastHwVSync[disp]) {
                ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
                        timestamp);
                return;
            }

            mLastHwVSync[disp] = timestamp;
        }

        char tag[16];
        snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
        ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);

        mEventHandler.onVSyncReceived(disp, timestamp);
    }
}

最終會通知mEventHandler的消息,這個handler從那裡來的呢?

void SurfaceFlinger::init(){

 mHwc = new HWComposer(this,
            *static_cast<HWComposer::EventHandler *>(this));
}

Yes,handler就是SurfaceFlinger,對嘛。SurfaceFlinger就是Surface合成的總管,所以這個信號一定會被它接收。

class SurfaceFlinger : public BnSurfaceComposer,
                       private IBinder::DeathRecipient,
                       private HWComposer::EventHandler
 

8.2.2軟件模擬信號

bool HWComposer::VSyncThread::threadLoop() {
    { // scope for lock
        Mutex::Autolock _l(mLock);
        while (!mEnabled) {
            mCondition.wait(mLock);
        }
    }

    const nsecs_t period = mRefreshPeriod;
    const nsecs_t now = systemTime(CLOCK_MONOTONIC);
    nsecs_t next_vsync = mNextFakeVSync;
    nsecs_t sleep = next_vsync - now;
    if (sleep < 0) {
        // we missed, find where the next vsync should be
        sleep = (period - ((now - next_vsync) % period));
        next_vsync = now + sleep;
    }
    mNextFakeVSync = next_vsync + period;

    struct timespec spec;
    spec.tv_sec  = next_vsync / 1000000000;
    spec.tv_nsec = next_vsync % 1000000000;

    int err;
    do {
        err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
    } while (err<0 && errno == EINTR);

    if (err == 0) {
        mHwc.mEventHandler.onVSyncReceived(0, next_vsync);
    }

    return true;
}

判斷系統Vsync信號開關。然後計算下一次刷新的時間點。

 const nsecs_t period = mRefreshPeriod;

刷新間隔,CLOCK_MONOTONIC是從系統開機後的時間間隔(tick累加)

得到需要等待的時間sleep,和下一次vsync信號的時間點。

然後一個do while的操作,來等待信號時間點的到來。

最後,發出這個信號。

這裡還有個情況,就是一開始的地方,mEnable變量,系統可以設置enable來控制vsync信號的產生。

void HWComposer::VSyncThread::setEnabled(bool enabled) 

 

8.3 SurfaceFlinger處理Vsync信號

在4.4以前,Vsync的處理通過EventThread就可以了。但是KK再次對這段邏輯進行細化和復雜化。Google真是費勁心思為了提升性能。

先來直接看下Surfaceflinger的onVSyncReceived函數:

void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
    bool needsHwVsync = false;

    { // Scope for the lock
        Mutex::Autolock _l(mHWVsyncLock);
        if (type == 0 && mPrimaryHWVsyncEnabled) {
            needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);//mPromaryDisplays是什麼?
        }
    }

    if (needsHwVsync) {
        enableHardwareVsync();//做了什麼
    } else {
        disableHardwareVsync(false);//做了什麼
  } 

}

雖然很短,但是乍一看還是一頭霧水

mPrimaryHWVsyncEnabled是什麼時候被賦值的?

mPrimaryDispSync是什麼,addResyncSample又做了什麼?

enableHardwareVsync &disableHardwareVsync在干什麼?

要解答這些問題,就從SurfaceFlinger::init開始看

void SurfaceFlinger::init() { ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); status_t err; Mutex::Autolock _l(mStateLock); /* Set the mask bit of the sigset to block the SIGPIPE signal */ sigset_t sigMask; sigemptyset (&sigMask); sigaddset(&sigMask, SIGPIPE); sigprocmask(SIG_BLOCK, &sigMask, NULL); // initialize EGL for the default display mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(mEGLDisplay, NULL, NULL); // Initialize the H/W composer object. There may or may not be an // actual hardware composer underneath. mHwc = new HWComposer(this, *static_cast<HWComposer::EventHandler *>(this)); // get a RenderEngine for the given display / config (can't fail) mRenderEngine = RenderEngine::create(mEGLDisplay, mHwc->getVisualID()); // retrieve the EGL context that was selected/created mEGLContext = mRenderEngine->getEGLContext(); LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, "couldn't create EGLContext"); // initialize our non-virtual displays for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) { DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i); // set-up the displays that are already connected if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) { #ifdef QCOM_BSP // query from hwc if the non-virtual display is secure. bool isSecure = mHwc->isSecure(i);; #else // All non-virtual displays are currently considered secure bool isSecure = true; #endif createBuiltinDisplayLocked(type, isSecure); wp<IBinder> token = mBuiltinDisplays[i]; sp<IGraphicBufferProducer> producer; sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&producer, &consumer, new GraphicBufferAlloc()); sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i, consumer); int32_t hwcId = allocateHwcDisplayId(type); sp<DisplayDevice> hw = new DisplayDevice(this, type, hwcId, mHwc->getFormat(hwcId), isSecure, token, fbs, producer, mRenderEngine->getEGLConfig()); if (i > DisplayDevice::DISPLAY_PRIMARY) { // FIXME: currently we don't get blank/unblank requests // for displays other than the main display, so we always // assume a connected display is unblanked. ALOGD("marking display %zu as acquired/unblanked", i); hw->setPowerMode(HWC_POWER_MODE_NORMAL); } mDisplays.add(token, hw); } } // make the GLContext current so that we can create textures when creating Layers // (which may happens before we render something) getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext); // start the EventThread sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync, vsyncPhaseOffsetNs, true, "app"); mEventThread = new EventThread(vsyncSrc); sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, sfVsyncPhaseOffsetNs, true, "sf"); mSFEventThread = new EventThread(sfVsyncSrc); mEventQueue.setEventThread(mSFEventThread); mEventControlThread = new EventControlThread(this); mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY); android_set_rt_ioprio(mEventControlThread->getTid(), 1); // set a fake vsync period if there is no HWComposer if (mHwc->initCheck() != NO_ERROR) { mPrimaryDispSync.setPeriod(16666667); } // initialize our drawing state mDrawingState = mCurrentState; // set initial conditions (e.g. unblank default device) initializeDisplays(); // start boot animation startBootAnim(); } SurfaceFlinger::init

有2個幾乎一樣的DispSyncSource,它的目的是提供了Vsync的虛擬化。關於這塊的分析,可以參考Android 4.4(KitKat)中VSync信號的虛擬化

在三緩沖的框架下,對於一幀內容,先等APP UI畫完了,SurfaceFlinger再出場整合到FrameBuffer

而現在google就是讓它們一起跑起來。

然後搞了2個延時,這樣就不會有問題。對應vsyncSrc(繪圖延時) & sfVsyncSrc(合成延時)

8.3.1 EventThread

bool EventThread::threadLoop() {
    DisplayEventReceiver::Event event;
    Vector< sp<EventThread::Connection> > signalConnections;
    signalConnections = waitForEvent(&event);

    // dispatch events to listeners...
    const size_t count = signalConnections.size();
    for (size_t i=0 ; i<count ; i++) {
        const sp<Connection>& conn(signalConnections[i]);
        // now see if we still need to report this event
        status_t err = conn->postEvent(event);
        if (err == -EAGAIN || err == -EWOULDBLOCK) {
            // The destination doesn't accept events anymore, it's probably
            // full. For now, we just drop the events on the floor.
            // FIXME: Note that some events cannot be dropped and would have
            // to be re-sent later.
            // Right-now we don't have the ability to do this.
            ALOGW("EventThread: dropping event (%08x) for connection %p",
                    event.header.type, conn.get());
        } else if (err < 0) {
            // handle any other error on the pipe as fatal. the only
            // reasonable thing to do is to clean-up this connection.
            // The most common error we'll get here is -EPIPE.
            removeDisplayEventConnection(signalConnections[i]);
        }
    }
    return true;
}

 EventThread會發送消息到surfaceflinger裡面的MessageQueue。

MessageQueue處理消息:

int MessageQueue::eventReceiver(int /*fd*/, int /*events*/) {
    ssize_t n;
    DisplayEventReceiver::Event buffer[8];
    while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) {
        for (int i=0 ; i<n ; i++) {
            if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
#if INVALIDATE_ON_VSYNC
                mHandler->dispatchInvalidate();
#else
                mHandler->dispatchRefresh();
#endif
                break;
            }
        }
    }
    return 1;
}

如果Event的類型是

DisplayEventReceiver::DISPLAY_EVENT_VSYNC

正是我們需要的類型,所以,就有2中處理方式:

UI進程需要先准備好數據(invalidate),然後Vsync信號來了以後,就開始刷新屏幕。

SurfaceFlinger是在Vsync來臨之際准備數據然後刷新,還是平常就准備當VSync來臨是再刷新。

先來看dispatchInvalidate,最後處理的地方就是這裡。

        case MessageQueue::INVALIDATE: {
            bool refreshNeeded = handleMessageTransaction();
            refreshNeeded |= handleMessageInvalidate();
            refreshNeeded |= mRepaintEverything;
            if (refreshNeeded) {
                // Signal a refresh if a transaction modified the window state,
                // a new buffer was latched, or if HWC has requested a full
                // repaint
                signalRefresh();
            }
            break;
        }

我們來看下handleMessageRefresh:

void SurfaceFlinger::handleMessageRefresh() {
    ATRACE_CALL();
    preComposition();  //合成前的准備
    rebuildLayerStacks();//重新建立layer堆棧
    setUpHWComposer();//HWComposer的設定
#ifdef QCOM_BSP
    setUpTiledDr();
#endif
    doDebugFlashRegions();
    doComposition();  //正式合成工作
    postComposition(); //合成的後期工作
}

 

8.3.2handleMessageTransaction

 handleMessageTransaction在簡單判斷後直接調用handlerTransaction。

可以看到裡面的handleTransactionLocked才是代碼真正處理的地方。

void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { const LayerVector& currentLayers(mCurrentState.layersSortedByZ); const size_t count = currentLayers.size(); /* * Traversal of the children * (perform the transaction for each of them if needed) */ if (transactionFlags & eTraversalNeeded) { for (size_t i=0 ; i<count ; i++) { const sp<Layer>& layer(currentLayers[i]); uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); if (!trFlags) continue; const uint32_t flags = layer->doTransaction(0); if (flags & Layer::eVisibleRegion) mVisibleRegionsDirty = true; } } /* * Perform display own transactions if needed */ if (transactionFlags & eDisplayTransactionNeeded) { // here we take advantage of Vector's copy-on-write semantics to // improve performance by skipping the transaction entirely when // know that the lists are identical const KeyedVector< wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays); const KeyedVector< wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays); if (!curr.isIdenticalTo(draw)) { mVisibleRegionsDirty = true; const size_t cc = curr.size(); size_t dc = draw.size(); // find the displays that were removed // (ie: in drawing state but not in current state) // also handle displays that changed // (ie: displays that are in both lists) for (size_t i=0 ; i<dc ; i++) { const ssize_t j = curr.indexOfKey(draw.keyAt(i)); if (j < 0) { // in drawing state but not in current state if (!draw[i].isMainDisplay()) { // Call makeCurrent() on the primary display so we can // be sure that nothing associated with this display // is current. const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDevice()); defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext); sp<DisplayDevice> hw(getDisplayDevice(draw.keyAt(i))); if (hw != NULL) hw->disconnect(getHwComposer()); if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) mEventThread->onHotplugReceived(draw[i].type, false); mDisplays.removeItem(draw.keyAt(i)); } else { ALOGW("trying to remove the main display"); } } else { // this display is in both lists. see if something changed. const DisplayDeviceState& state(curr[j]); const wp<IBinder>& display(curr.keyAt(j)); if (state.surface->asBinder() != draw[i].surface->asBinder()) { // changing the surface is like destroying and // recreating the DisplayDevice, so we just remove it // from the drawing state, so that it get re-added // below. sp<DisplayDevice> hw(getDisplayDevice(display)); if (hw != NULL) hw->disconnect(getHwComposer()); mDisplays.removeItem(display); mDrawingState.displays.removeItemsAt(i); dc--; i--; // at this point we must loop to the next item continue; } const sp<DisplayDevice> disp(getDisplayDevice(display)); if (disp != NULL) { if (state.layerStack != draw[i].layerStack) { disp->setLayerStack(state.layerStack); } if ((state.orientation != draw[i].orientation) || (state.viewport != draw[i].viewport) || (state.frame != draw[i].frame)) { #ifdef QCOM_BSP int orient = state.orientation; // Honor the orientation change after boot // animation completes and make sure boot // animation is shown in panel orientation always. if(mBootFinished){ disp->setProjection(state.orientation, state.viewport, state.frame); orient = state.orientation; } else{ char property[PROPERTY_VALUE_MAX]; int panelOrientation = DisplayState::eOrientationDefault; if(property_get("persist.panel.orientation", property, "0") > 0){ panelOrientation = atoi(property) / 90; } disp->setProjection(panelOrientation, state.viewport, state.frame); orient = panelOrientation; } // Set the view frame of each display only of its // default orientation. if(orient == DisplayState::eOrientationDefault and state.frame.isValid()) { qdutils::setViewFrame(disp->getHwcDisplayId(), state.frame.left, state.frame.top, state.frame.right, state.frame.bottom); } #else disp->setProjection(state.orientation, state.viewport, state.frame); #endif } if (state.width != draw[i].width || state.height != draw[i].height) { disp->setDisplaySize(state.width, state.height); } } } } // find displays that were added // (ie: in current state but not in drawing state) for (size_t i=0 ; i<cc ; i++) { if (draw.indexOfKey(curr.keyAt(i)) < 0) { const DisplayDeviceState& state(curr[i]); sp<DisplaySurface> dispSurface; sp<IGraphicBufferProducer> producer; sp<IGraphicBufferProducer> bqProducer; sp<IGraphicBufferConsumer> bqConsumer; BufferQueue::createBufferQueue(&bqProducer, &bqConsumer, new GraphicBufferAlloc()); int32_t hwcDisplayId = -1; if (state.isVirtualDisplay()) { // Virtual displays without a surface are dormant: // they have external state (layer stack, projection, // etc.) but no internal state (i.e. a DisplayDevice). if (state.surface != NULL) { configureVirtualDisplay(hwcDisplayId, dispSurface, producer, state, bqProducer, bqConsumer); } } else { ALOGE_IF(state.surface!=NULL, "adding a supported display, but rendering " "surface is provided (%p), ignoring it", state.surface.get()); hwcDisplayId = allocateHwcDisplayId(state.type); // for supported (by hwc) displays we provide our // own rendering surface dispSurface = new FramebufferSurface(*mHwc, state.type, bqConsumer); producer = bqProducer; } const wp<IBinder>& display(curr.keyAt(i)); if (dispSurface != NULL && producer != NULL) { sp<DisplayDevice> hw = new DisplayDevice(this, state.type, hwcDisplayId, mHwc->getFormat(hwcDisplayId), state.isSecure, display, dispSurface, producer, mRenderEngine->getEGLConfig()); hw->setLayerStack(state.layerStack); hw->setProjection(state.orientation, state.viewport, state.frame); hw->setDisplayName(state.displayName); // When a new display device is added update the active // config by querying HWC otherwise the default config // (config 0) will be used. int activeConfig = mHwc->getActiveConfig(hwcDisplayId); if (activeConfig >= 0) { hw->setActiveConfig(activeConfig); } mDisplays.add(display, hw); if (state.isVirtualDisplay()) { if (hwcDisplayId >= 0) { mHwc->setVirtualDisplayProperties(hwcDisplayId, hw->getWidth(), hw->getHeight(), hw->getFormat()); } } else { mEventThread->onHotplugReceived(state.type, true); } } } } } } if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) { // The transform hint might have changed for some layers // (either because a display has changed, or because a layer // as changed). // // Walk through all the layers in currentLayers, // and update their transform hint. // // If a layer is visible only on a single display, then that // display is used to calculate the hint, otherwise we use the // default display. // // NOTE: we do this here, rather than in rebuildLayerStacks() so that // the hint is set before we acquire a buffer from the surface texture. // // NOTE: layer transactions have taken place already, so we use their // drawing state. However, SurfaceFlinger's own transaction has not // happened yet, so we must use the current state layer list // (soon to become the drawing state list). // sp<const DisplayDevice> disp; uint32_t currentlayerStack = 0; for (size_t i=0; i<count; i++) { // NOTE: we rely on the fact that layers are sorted by // layerStack first (so we don't have to traverse the list // of displays for every layer). const sp<Layer>& layer(currentLayers[i]); uint32_t layerStack = layer->getDrawingState().layerStack; if (i==0 || currentlayerStack != layerStack) { currentlayerStack = layerStack; // figure out if this layerstack is mirrored // (more than one display) if so, pick the default display, // if not, pick the only display it's on. disp.clear(); for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { sp<const DisplayDevice> hw(mDisplays[dpy]); if (hw->getLayerStack() == currentlayerStack) { if (disp == NULL) { disp = hw; } else { disp = NULL; break; } } } } if (disp == NULL) { // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to // redraw after transform hint changes. See bug 8508397. // could be null when this layer is using a layerStack // that is not visible on any display. Also can occur at // screen off/on times. disp = getDefaultDisplayDevice(); } layer->updateTransformHint(disp); } } /* * Perform our own transaction if needed */ const LayerVector& layers(mDrawingState.layersSortedByZ); if (currentLayers.size() > layers.size()) { // layers have been added mVisibleRegionsDirty = true; } // some layers might have been removed, so // we need to update the regions they're exposing. if (mLayersRemoved) { mLayersRemoved = false; mVisibleRegionsDirty = true; const size_t count = layers.size(); for (size_t i=0 ; i<count ; i++) { const sp<Layer>& layer(layers[i]); if (currentLayers.indexOf(layer) < 0) { // this layer is not visible anymore // TODO: we could traverse the tree from front to back and // compute the actual visible region // TODO: we could cache the transformed region const Layer::State& s(layer->getDrawingState()); Region visibleReg = s.transform.transform( Region(Rect(s.active.w, s.active.h))); invalidateLayerStack(s.layerStack, visibleReg); } } } commitTransaction(); updateCursorAsync(); } handleTransactionLocked

這裡處理3中情況,過程類似,我們只看eTraversalNeeded這種情況。

 uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);

獲取各個layer的標志位,然後做const uint32_t flags = layer->doTransaction(0);的操作

各layer計算各自的可見區域,mVisibleRegionsDirty記錄可見區域變化。

以下代碼:

mCurrentState.layersSortedByZ

surfaceFlinger有2個記錄layer變化的全局變量

State mDrawingState;
State mCurrentState;

一個記錄上一次的狀態,後者記錄當前的狀態,這樣就可以判斷layer的變化狀態。layersSortedByZ 可見,layer是通過Z-order排列的。

這個變量記錄了所有的layer。

我們來看下

uint32_t Layer::doTransaction(uint32_t flags) {
ATRACE_CALL();

const Layer::State& s(getDrawingState());
const Layer::State& c(getCurrentState());

const bool sizeChanged = (c.requested.w != s.requested.w) ||
(c.requested.h != s.requested.h);

if (sizeChanged) {
// the size changed, we need to ask our client to request a new buffer
ALOGD_IF(DEBUG_RESIZE,
"doTransaction: geometry (layer=%p '%s'), tr=%02x, scalingMode=%d\n"
" current={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
" requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n"
" drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
" requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n",
this, getName().string(), mCurrentTransform, mCurrentScalingMode,
c.active.w, c.active.h,
c.active.crop.left,
c.active.crop.top,
c.active.crop.right,
c.active.crop.bottom,
c.active.crop.getWidth(),
c.active.crop.getHeight(),
c.requested.w, c.requested.h,
c.requested.crop.left,
c.requested.crop.top,
c.requested.crop.right,
c.requested.crop.bottom,
c.requested.crop.getWidth(),
c.requested.crop.getHeight(),
s.active.w, s.active.h,
s.active.crop.left,
s.active.crop.top,
s.active.crop.right,
s.active.crop.bottom,
s.active.crop.getWidth(),
s.active.crop.getHeight(),
s.requested.w, s.requested.h,
s.requested.crop.left,
s.requested.crop.top,
s.requested.crop.right,
s.requested.crop.bottom,
s.requested.crop.getWidth(),
s.requested.crop.getHeight());

// record the new size, form this point on, when the client request
// a buffer, it'll get the new size.
mSurfaceFlingerConsumer->setDefaultBufferSize(
c.requested.w, c.requested.h);
}

if (!isFixedSize()) {

const bool resizePending = (c.requested.w != c.active.w) ||
(c.requested.h != c.active.h);

if (resizePending) {
// don't let Layer::doTransaction update the drawing state
// if we have a pending resize, unless we are in fixed-size mode.
// the drawing state will be updated only once we receive a buffer
// with the correct size.
//
// in particular, we want to make sure the clip (which is part
// of the geometry state) is latched together with the size but is
// latched immediately when no resizing is involved.

flags |= eDontUpdateGeometryState;
}
}

// always set active to requested, unless we're asked not to
// this is used by Layer, which special cases resizes.
if (flags & eDontUpdateGeometryState) {
} else {
Layer::State& editCurrentState(getCurrentState());
editCurrentState.active = c.requested;
}

if (s.active != c.active) {
// invalidate and recompute the visible regions if needed
flags |= Layer::eVisibleRegion;
}

if (c.sequence != s.sequence) {
// invalidate and recompute the visible regions if needed
flags |= eVisibleRegion;
this->contentDirty = true;

// we may use linear filtering, if the matrix scales us
const uint8_t type = c.transform.getType();
mNeedsFiltering = (!c.transform.preserveRects() ||
(type >= Transform::SCALE));
}

// Commit the transaction
commitTransaction();
return flags;
}

首先判斷size是否有修改,然後

mSurfaceFlingerConsumer->setDefaultBufferSize

重新獲取大小。

if (c.sequence != s.sequence) {
        // invalidate and recompute the visible regions if needed
        flags |= eVisibleRegion;

Sequence是個什麼東西?

當Layer的position,Zorder,alpha,matrix,transparent region,flags,crops.等發生變化的時候,sequence就會自增。

也就是,當這些屬性發生變化是,頁面在Vsync信號觸發的時候,根據sequence來判斷是否需要屬性頁面。

新增layer,

對比2個state中的layer隊列,就可以知道新增的layer。

移除layer,

也是比較2個layer隊列,就可以找到移除的layer。

提交transaction,主要就是同步2個state。然後currentstate繼續跟蹤layer變化,如此往復。

 

Vsync 是SurfaceFlinger模塊最核心的概念,所以這塊將會分多次講解。

 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved