• android Gui系统之SurfaceFlinger(4)---Vsync(1)


    8.Vsync

    8.1概论

    VSYNC(Vertical Synchronization)是一个相当古老的概念,对于游戏玩家,它有一个更加大名鼎鼎的中文名字—-垂直同步。

    “垂直同步(vsync)”指的是显卡的输出帧数和屏幕的垂直刷新率相同,这完全是一个CRT显示器上的概念。其实无论是VSYNC还是垂直同步这个名字,

    因为LCD根本就没有垂直扫描的这种东西,因此这个名字本身已经没有意义。但是基于历史的原因,这个名称在图形图像领域被沿袭下来。
    在当下,垂直同步的含义我们可以理解为,使得显卡生成帧的速度和屏幕刷新的速度的保持一致。举例来说,如果屏幕的刷新率为60Hz,那么生成帧

    的速度就应该被固定在1/60 s。

    8.2 VSync信号的产生和分发

    VSync信号的产生在android_frameworks_nativeservicessurfaceflingerDisplayHardwareHWComposer.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 "
    " current={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) } "
    " requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }} "
    " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) } "
    " requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }} ",
    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模块最核心的概念,所以这块将会分多次讲解。

  • 相关阅读:
    MVC ActionResult JsonResult
    xml文件
    使用socket实现聊天功能
    使用多线程完成Socket
    Socket编程
    U1总结
    多线程
    IO
    单例模式
    日期
  • 原文地址:https://www.cnblogs.com/deman/p/5600886.html
Copyright © 2020-2023  润新知