SurfaceFlinger图像合成[1]

Layer接收到新的GraphicBuffer

void Layer::onFrameAvailable(const BufferItem& item) {
    // 将新的Buffer添加到Layer内部的mQueueItems队列进行处理
    { 
        ....
        //将 BufferItem放入Layer队列中
        mQueueItems.push_back(item);
        //Layer中待处理Buffer +1
        android_atomic_inc(&mQueuedFrames);

        // Wake up any pending callbacks
        mLastFrameNumberReceived = item.mFrameNumber;
        ....
    }
   //通知SurfaceFlinger进行更新
    mFlinger->signalLayerUpdate();
}

Layer中接收到其生产者产生的GraphicBuffer后会接收到onFrameAvailable的通知,Layer将新的Buffer信息放入自己的mQueueItems队列中等待合成,待合成的Buffer数量+1,最后调用signalLayerUpdate通知SurfaceFlinger合成.

void SurfaceFlinger::signalLayerUpdate() {
    mEventQueue.invalidate();
}

void MessageQueue::invalidate() {
    ......
    mEvents->requestNextVsync();
    ......
}

signalLayerUpdate方法调用了MessageQueue的invalidate方法,而invalidate又调用了requestNextVsync方法,这个方法在Vsync分析的时候已经了解过,主要作用是通知Vsync机制在下一次SF的Vsync到来的时候唤醒SF进行工作. 而SF在接收到下次Vsync到来的时候便会执行图形合成.
再来看下SF接收到Vsync的处理流程

void SurfaceFlinger::onMessageReceived(int32_t what) {
    ATRACE_CALL();
    switch (what) {
        ......
        //Vsync到来执行invalidate方法
        case MessageQueue::INVALIDATE: {
            bool refreshNeeded = handleMessageTransaction();
            refreshNeeded |= handleMessageInvalidate();
            refreshNeeded |= mRepaintEverything;
            if (refreshNeeded) {
                // 更加更新结果决定是否需要进行刷新屏幕显示,如果窗口状态发生了变化,则需要重新合成并刷新屏幕显示.
                signalRefresh();
            }
            break;
        }
        //合成UI刷新到屏幕
        case MessageQueue::REFRESH: {
            handleMessageRefresh();
            break;
        }
    }
}

SF图形合成又大体上分为了两个部分
1:SF更新合成相关的信息
2:SF执行合成操作并显示

SF根据更新结果来决定是否需要再次合成并显示,

SF更新合成相关的信息

handleMessageTransaction

handleMessageTransaction主要处理Layer属性变化, 显示设备变化等情况,最终将变化的信息mCurrentState提交到mDrawingState, 等待合成处理.

handleMessageTransaction方法经过层层调用最终执行到 handleTransactionLocked方法中,我们直接看这个方法.
SF有两个状态 mDrawingState表示正在绘制显示的状态,mCurrentState表示从上次 绘制后 发生变化的信息. 修改的信息都保存在mCurrentState中,等到修改完成后统一提交到mDrawingState中。

void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
    //获取mCurrentState中所有的Layer。
    const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
    const size_t count = currentLayers.size();

    //遍历mCurrentState中所有的Layer,对发生变化的Layer执行doTransaction函数,判断Layer的可见区域是否发生了变化
    if (transactionFlags & eTraversalNeeded) {
        for (size_t i=0 ; i<count ; i++) {
            const sp<Layer>& layer(currentLayers[i]);
            //根据eTransactionNeeded,判断Layer是否发生了变化,Layer发生变化后会设置这个flag
            uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
            if (!trFlags) continue;

            //Layer的doTransaction函数会会对比Layer的旧的状态和新的状态是否发生变化,当Layer的可见区域大小发生变化之后,设置mVisibleRegionsDirty为true
            const uint32_t flags = layer->doTransaction(0);
            if (flags & Layer::eVisibleRegion)
                mVisibleRegionsDirty = true;
        }
    }

handleTransactionLocked第一部分:检查Layer VisibleRegion是否发生变化.
遍历所有的Layer查看SF的visibleRegion是否发生了变化,首先会先检查Layer是否发生了变化, Layer没有发生变化则不需要检查该Layer,如果Layer发生了变化,需要对比该Layer的显示区域和原来显示区域是否发生变化,若变化设置mVisibleRegionsDirty为true。

    //遍历并检查所有的显示设备,检查显示设备是否发生了增加或者减少.并做相应的处理
    if (transactionFlags & eDisplayTransactionNeeded) {
        //两个列表来保存上次合成时显示设备的信息和当前显示设备的信息
        // draw 上次合成时显示设备信息
        // curr 当前显示设备的信息
        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();

            // 找到删除的显示设备信息
            // (ie: 在draw列表中,但是却不在curr列表中,说明有设备删除)
            // 处理显示设备发生变化
            // (ie: 两个列表中都有该显示设备)
            for (size_t i=0 ; i<dc ; i++) {
                const ssize_t j = curr.indexOfKey(draw.keyAt(i));
                if (j < 0) {
                    // 1: 显示设备移除: 在draw列表中,却不在curr列表中
                    if (!draw[i].isMainDisplay()) {
                        // 如果有设备移除,切当前设备不是主显示设备的时候,将EGL的Context设置到默认的主显示设备
                        // 从HWC断开该设备,通知EventThread设备热插拔事件,从Display列表移除
                        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 {
                        // 主设备不允许移除,打印Warnning 提示信息
                        ALOGW("trying to remove the main display");
                    }
                } else {
                    // 设备在两个列表中都有,但是有信息发生了变化
                    const DisplayDeviceState& state(curr[j]);
                    const wp<IBinder>& display(curr.keyAt(j));
                    const sp<IBinder> state_binder = IInterface::asBinder(state.surface);
                    const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface);
                    if (state_binder != draw_binder) {
                        // 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))
                        {
                            disp->setProjection(state.orientation,
                                    state.viewport, state.frame);
                        }
                        if (state.width != draw[i].width || state.height != draw[i].height) {
                            disp->setDisplaySize(state.width, state.height);
                        }
                    }
                }
            }

            // 找到新添加的Display设备信息
            // (ie: draw列表中没有,curr列表中有该设备,说明有新设备添加进来)
            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()) {
                        // 虚拟显示设备暂时不关注
                        if (state.surface != NULL) {

                            int width = 0;
                            int status = state.surface->query(
                                    NATIVE_WINDOW_WIDTH, &width);
                            ALOGE_IF(status != NO_ERROR,
                                    "Unable to query width (%d)", status);
                            int height = 0;
                            status = state.surface->query(
                                    NATIVE_WINDOW_HEIGHT, &height);
                            ALOGE_IF(status != NO_ERROR,
                                    "Unable to query height (%d)", status);
                            if (MAX_VIRTUAL_DISPLAY_DIMENSION == 0 ||
                                    (width <= MAX_VIRTUAL_DISPLAY_DIMENSION &&
                                     height <= MAX_VIRTUAL_DISPLAY_DIMENSION)) {
                                hwcDisplayId = allocateHwcDisplayId(state.type);
                            }

                            sp<VirtualDisplaySurface> vds = new VirtualDisplaySurface(
                                    *mHwc, hwcDisplayId, state.surface,
                                    bqProducer, bqConsumer, state.displayName);

                            dispSurface = vds;
                            producer = vds;
                        }
                    } else {
                        //为新添加的设备分配HWC ID,并创建FramebufferSurface消费者.
                        ALOGE_IF(state.surface!=NULL,
                                "adding a supported display, but rendering "
                                "surface is provided (%p), ignoring it",
                                state.surface.get());
                        hwcDisplayId = allocateHwcDisplayId(state.type);
                        dispSurface = new FramebufferSurface(*mHwc, state.type,
                                bqConsumer);
                        producer = bqProducer;
                    }

                    const wp<IBinder>& display(curr.keyAt(i));
                    if (dispSurface != NULL) {
                        //创建该显示设备的DisplayDevice,并添加到mDisplays中.
                        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);
                        mDisplays.add(display, hw);
                        if (state.isVirtualDisplay()) {
                            if (hwcDisplayId >= 0) {
                                mHwc->setVirtualDisplayProperties(hwcDisplayId,
                                        hw->getWidth(), hw->getHeight(),
                                        hw->getFormat());
                            }
                        } else {
                            // 通知EventThread有新设备热插拔
                            mEventThread->onHotplugReceived(state.type, true);
                        }
                    }
                }
            }
        }
    }

handleTransactionLocked第二部分:检查显示设备是否发生变化
1:检查Display是否移除,则更新SF移除相关的信息
2:检查Display是否发生变化, 若发生变化则需要将Display相关的信息更新为新的显示设备信息
3:检查Display是否添加新设备,若添加新设备,则按照设备添加流程为新设备创建BufferQueue和FrameBufferSurface等.

    //当显示设备发生变化或者某些Layer发生变化后,需要修改Layer的transform hint, 使Layer视图的矩阵变化。
    //遍历mCurrentState所有的Layer并更新他的transform hint
    //如果一个Layer只显示在一个显示设备上,那我们就用这个显示设备来计算他的Transform hint,如果显示在多个显示设备上,则需要按照默认主显示设备计算.
    if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) {
        
        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;
                //根据当前Layer的layerStack找到所属的显示设备Display
                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) {
                //如果显示在过个显示设备上,则使用默认显示设备
                disp = getDefaultDisplayDevice();
            }
            //将显示设备信息更新到Layer中
            layer->updateTransformHint(disp);
        }
    }

handleTransactionLocked第三部分:更新transform hint相关信息
当显示设备发生变化或者某些Layer发生变化后,需要修改Layer的transform hint.

    
    //如有有新添加的Layer, 则mVisibleRegionsDirty = true
    const LayerVector& layers(mDrawingState.layersSortedByZ);
    if (currentLayers.size() > layers.size()) {
        // layers have been added
        mVisibleRegionsDirty = true;
    }

    // 如果有Layer移除, 该Layer原先的显示区域就是需要更新显示区域
    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) {
                const Layer::State& s(layer->getDrawingState());
                Region visibleReg = s.transform.transform(
                        Region(Rect(s.active.w, s.active.h)));
                invalidateLayerStack(s.layerStack, visibleReg);
            }
        }
    }

    commitTransaction();

}

handleTransactionLocked第四部分: 更新Layer信息
若有Layer移除,更新SF的visibleRegion, 说明原来该Layer显示的区域需要重新刷新显示
最后调用commitTransaction,提交mCurrentState信息, 将所有变化的信息更新完成后,mCurrentState提交到mDrawingState中. 下一步就要合成显示这些变化后的内容了.

handleMessageInvalidate

handleMessageInvalidate会调用handlePageFlip函数. 直接看handlePageFlip的逻辑

handlePageFlip

bool SurfaceFlinger::handlePageFlip()
{
    Region dirtyRegion;

    bool visibleRegions = false;
    //拿到mDrawingState中的所有Layer, 就是我们上一步中刚提交的变化的Layer
    const LayerVector& layers(mDrawingState.layersSortedByZ);
    bool frameQueued = false;

    //遍历所有的Layer, 找到有新的Buffer到来需要合成的Layer,将这些Layer添加到layersWithQueuedFrames列表中.
    //那些Layer需要合成呢?
    // 1:Layer中有新的待处理的Buffer
    // 2:Buffer需要立刻显示的。(未到指定显示时间的不需要处理)
    Vector<Layer*> layersWithQueuedFrames;
    for (size_t i = 0, count = layers.size(); i<count ; i++) {
        const sp<Layer>& layer(layers[i]);
        if (layer->hasQueuedFrame()) {
            frameQueued = true;
            if (layer->shouldPresentNow(mPrimaryDispSync)) {
                layersWithQueuedFrames.push_back(layer.get());
            } else {
                layer->useEmptyDamage();
            }
        } else {
            layer->useEmptyDamage();
        }
    }
    //遍历所有需要处理的Layer,并从BufferQueue中获取Buffer并更新,最终更新到Display的visibleRegion中
    for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) {
        Layer* layer = layersWithQueuedFrames[i];
        //latchBuffer是在BufferQueue中分析过,从BufferQueue中获取Buffer,并将Buffer绑定到Layer对应的纹理上.
        const Region dirty(layer->latchBuffer(visibleRegions));
        layer->useSurfaceDamage();
        const Layer::State& s(layer->getDrawingState());
        //将Layer的visibleRegion 更新到对应显示设备的Display上.
        invalidateLayerStack(s.layerStack, dirty);
    }

    mVisibleRegionsDirty |= visibleRegions;

    // Layer有待处理的Buffer,但是不到显示时间,则设置下一个Vsync到来的时候唤醒SF进行处理.
    if (frameQueued && layersWithQueuedFrames.empty()) {
        signalLayerUpdate();
    }

    // 如果有需要处理的Layer, layersWithQueuedFrames中有数据,则需要刷新合成
    return !layersWithQueuedFrames.empty();
}

handlePageFlip方法主要来处理Layer Buffer相关的内容.
1: 找到此次Vsync事件中有需要处理的Buffer的Layer。
2: 遍历所有需要待处理的Layer, 从BufferQueue中拿出该Layer对应的Buffer,更新到Layer对应的纹理中, 计算Layer的visible区域,更新到对应显示设备的DisplayDevice上。
3: 判断Layer是否有待处理但是还没有到指定事件的Buffer, 如果有则需要下次Vsync事件在处理,调用signalLayerUpdate预约下次Vsync事件.
4: 返回结果:如果此次Vsync有要处理的Layer,则说明需要重新合成,返回结果为true。

总结

此时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();
    }

Vsync到来时,INVALIDATE过程主要处理了 SF中距上次合成后的一些变化信息。
1:handleMessageTransaction 处理了Layer属性变化, 显示设备变化等情况,然后将变化的信息mCurrentState提交到了mDrawingState,等待合成处理.
主要包括Layer属性发生变化,显示设备添加和移除的处理,更新显示设备的transform hint相关的信息,处理Layer移除和增加等相关的信息,如果这些信息发生变化, 则需要重新合成刷新显示。
2:handleMessageInvalidate 更新了Layer的buffer内容到Layer的纹理
找到有待处理Buffer的Layer, 将Layer的buffer从BufferQueue中拿到,更新到纹理中. 如果内容发生变化,需要重新刷新合成.
3:mRepaintEverything 表示HWC硬件要求强制刷新

当以上过程中有对应的条件发生了变化,就会调用signalRefresh,通知SF进行合成刷新.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269