android 使用SurfaceFlinger 服务的流程分析,基于4.4(三)----图像的输出过程

2023-10-26

经过前面两篇的介绍,现在可以分析surfaceflinger 的处理UI buffer的流程了

目录

一、onMessageReceived 

1、handleMessageTransaction()

2、handleMessageInvalidate():

3、 signalRefresh();

 ① preComposition():

② rebuildLayerStacks():

③setUpHWComposer

④doComposition


一、onMessageReceived 

通过vsync机制知道,最终会跑到onMessageReceived函数 ::INVALIDATE这里,进行图像输出的准备工作。

void SurfaceFlinger::onMessageReceived(int32_t what) {
    ATRACE_CALL();
    switch (what) {
    case MessageQueue::TRANSACTION:
        handleMessageTransaction();
        break;
    case MessageQueue::INVALIDATE:
        handleMessageTransaction();
        handleMessageInvalidate();
        signalRefresh();
        break;
    case MessageQueue::REFRESH:
        handleMessageRefresh();
        break;
    }
}

case MessageQueue::INVALIDATE:会调用三个方法,分别看一下:

1、handleMessageTransaction()

void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
    .....
    /*1、
     * Traversal of the children
     * (perform the transaction for each of them if needed)
     */
    if (transactionFlags & eTraversalNeeded) {
        for (size_t i=0 ; i<count ; i++) {//这里遍历每一个Layer,根据eTraversalNeeded标志来决定是否要检查Layer对象。如果Layer中有eTransactionNeeded标志,则返回非0值,然后调用它的doTransaction函数
            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)//Layer的doTransaction函数返回的flags如果有eVisibleRegion,则说明该Layer需要更新,mVisibleRegionsDirty设置为true
                mVisibleRegionsDirty = true;
        }
    }
    /*2、
     * 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) {//两个对象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);
                        }
                    }
                }
            }
            //处理显示设备增加的情况。。。
            // find displays that were added
            // (ie: in current state but not in drawing state)
            for (size_t i=0 ; i<cc ; i++) {

            ...............................
            
    }
    3、
//这段代码根据每种显示设备的不同,设置和显示设备关联在一起的Layer(主要看Layer的layerStack是否和DisplayDevice的layerStack一致)的TransformHint(主要指设备的显示方向orientation)
    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).
       ..............................
       layer->updateTransformHint(disp);//设置Layer对象的TransformHint
    }

    /*4、
     * Perform our own transaction if needed
     */
    const LayerVector& layers(mDrawingState.layersSortedByZ);
    if (currentLayers.size() > layers.size()) {//如果有Layer加入,设置需要更新 
        // layers have been added
        mVisibleRegionsDirty = true;
    }
    // some layers might have been removed, so
    // we need to update the regions they're exposing.
    if (mLayersRemoved) {//有Layer删除
        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) {//如果这个Layer不存在,则把它的所在区域设置为需要更新的区域
                // 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();//commitTransaction函数最关键的作用是把mDrawingState的值设置成mCurrentState的值。
}

handleTransactionLocked 做了下面几件事:

①在 handleTransactionLocked 函数里面遍历每一个children,调用 layer->doTransaction(0),查看layer是否发生改变,如果是就把 mVisibleRegionsDirty 置为 true  。

②处理显示设备相关的事务,add、remove、change等。

  1. 移除不需要的显示设备,将其对应的DisplayDevice移除
  2. 对于发生变化的显示设备(设置Surface、重置layerStack、旋转。。。),就需要重置显示对象的属性
  3. 对于新增加的显示设备,创建DisplayDevice并加入到系统

③layer的角度发生变化处理。

④surfaceflinger 本身的事务处理,如layer的添加、删除等。

  1. 如果有Layer增加,需要重新计算设备的更新区域,mVisibleRegionsDirty设置为true
  2. 如果有Layer被删除,需要把Layer的可见区域加入到系统需要更新的区域中

①.1 分析doTransaction函数:

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

    const Layer::State& s(getDrawingState());//上次绘制使用的State对象
    const Layer::State& c(getCurrentState());//当前绘制使用的State对象

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

    if (sizeChanged) {//如果两个对象的大小不相等,说明Layer的尺寸发生变化
        // the size changed, we need to ask our client to request a new buffer
       

        // 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 {如果没有eDontUpdateGeometryState标志,更新active的值为request
        Layer::State& editCurrentState(getCurrentState());
        editCurrentState.active = c.requested;
    }

    if (s.active != c.active) {// 如果当前state的active和以前的State的active不等,设置更新标志 
        // invalidate and recompute the visible regions if needed
        flags |= Layer::eVisibleRegion;
    }

    if (c.sequence != s.sequence) {//如果当前state的sequence和以前state的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();//将mCurrentState的值赋给mDrawingState
    return flags;
}

其中Layer::State 是啥?

    struct State {
        Geometry active;//实际大小 
        Geometry requested;//用户大小
        uint32_t z;//Z轴值 
        uint32_t layerStack;//和显示设备的关联值
        uint8_t alpha;
        uint8_t flags;
        uint8_t reserved[2];
        int32_t sequence; // changes when visible regions can change
        Transform transform;//序列值,Layer的属性变化一次,这个值就加1
        // the transparentRegion hint is a bit special, it's latched only
        // when we receive a buffer -- this is because it's "content"
        // dependent.
        Region activeTransparentRegion;//实际的透明区域  
        Region requestedTransparentRegion;//用户层的透明区域 
    };

Layer对象在绘制图形时,使用的是mDrawingState变量,用户调用接口设置Layer对象属性是,设置的值保存在mCurrentState对象中,这样就不会因为用户的操作而干扰Layer对象的绘制了。所以这里有两个对象。

接下来对State 结构体中的一些变量进行说明:

  1. Geometry字段:State的结构中有两个Geometry字段,active和requested。他们表示layer的尺寸,其中requested保存是用户设置的尺寸,而active保存的值通过计算后的实际尺寸。
  2. layerStack字段:它是用户指定的一个值,用户可以给DisplayDevice也指定一个layerStack值,只有Layer对象和DisplayDevice对象的layerStack相等,这个Layer才能在这个显示设备上输出,这样的好处是可以让显示设备只显示某个Surface的内容。例如,可以让HDMI显示设备只显示手机上播放视频的Surface窗口,但不显示Activity窗口。
  3. sequence字段:它是一个序列值,每当用户调用了Layer的接口,例如setAlpha、setSize或者setLayer等改变Layer对象属性的哈数,这个值都会加1。因此在doTransaction函数中能通过比较sequence值来判断Layer的属性值有没有变化。

可以看到Layer::State中的layerStack中会对比DisplayDeviceState对象的layerStack,所以分析下DisplayDeviceState,定义在surfaceFlinger.h里面 ,代码如下:

    struct DisplayDeviceState {
        DisplayDeviceState();
        DisplayDeviceState(DisplayDevice::DisplayType type);
        bool isValid() const { return type >= 0; }
        bool isMainDisplay() const { return type == DisplayDevice::DISPLAY_PRIMARY; }
        bool isVirtualDisplay() const { return type >= DisplayDevice::DISPLAY_VIRTUAL; }
        DisplayDevice::DisplayType type;
        sp<IGraphicBufferProducer> surface;
        uint32_t layerStack;
        Rect viewport;
        Rect frame;
        uint8_t orientation;
        uint32_t width, height;
        String8 displayName;
        bool isSecure;
    };

DisplayDeviceState的layerStack和Layer的State中的layerStack如果相等,则Layer可以在该State对应的DisplayDevice中显示。

 

总结下,虽然处理了很多事物,但主要是设置一些flag,但并未对相关的Buffer进行实际的操作。handleTransaction函数的作用的就是处理系统在两次刷新期间的各种变化。SurfaceFlinger模块 中不管是SurfaceFlinger类还是Layer类,都采用了双缓冲的方式来保存他们的属性,这样的好处是刚改变SurfaceFlinger对象或者Layer类对象的属性时不需要上锁,这很大程度上提高了系统效率。只有在最后的图像输出才会进行一次上锁,并将内存的属性变化进行处理。正因此,应用进程必须收到VSync信号才开始改变Surface中Buffer的内容。

 

 

 

2、handleMessageInvalidate():
 

handleMessageInvalidate 里面主要干的事情是,让原来的图像数据失效,准备好新的图像数据,主要是在SurfaceFlingerConsumer 的那几步,也就是updateTextImage里面做的那几步。

这里解释一下UML里面几个重要的函数:

void SurfaceFlinger::handlePageFlip()
{
    Region dirtyRegion;

    bool visibleRegions = false;
    const LayerVector& layers(mDrawingState.layersSortedByZ);

    // Store the set of layers that need updates. This set must not change as
    // buffers are being latched, as this could result in a deadlock.
    // Example: Two producers share the same command stream and:
    // 1.) Layer 0 is latched
    // 2.) Layer 0 gets a new frame
    // 2.) Layer 1 gets a new frame
    // 3.) Layer 1 is latched.
    // Display is now waiting on Layer 1's frame, which is behind layer 0's
    // second frame. But layer 0's second frame could be waiting on display.
    Vector<Layer*> layersWithQueuedFrames;
    for (size_t i = 0, count = layers.size(); i<count ; i++) {
        const sp<Layer>& layer(layers[i]);
        if (layer->hasQueuedFrame())//确定这个Layer对象是否有需要更新的图层
            layersWithQueuedFrames.push_back(layer.get());//把需要更新的Layer对象放到layersWithQueuedFrames中
    }
    for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) {
        Layer* layer = layersWithQueuedFrames[i];
         //更新Layer对象的latchBuffer函数
        const Region dirty(layer->latchBuffer(visibleRegions));
        const Layer::State& s(layer->getDrawingState());
        //设置更新设备对象的更新区域
        invalidateLayerStack(s.layerStack, dirty);
    }

    mVisibleRegionsDirty |= visibleRegions;
}

layer的hasQueuedFrame()的代码实现如下:

bool hasQueuedFrame() const { return mQueuedFrames > 0 || mSidebandStreamChanged; }

只要Surface有数据写入,就会调用Layer的onFrameAvailable函数,然后mQueuedFrames值加1。

latchBuffer:

Region Layer::latchBuffer(bool& recomputeVisibleRegions)
{
    ...
 
    Region outDirtyRegion;
    if (mQueuedFrames > 0) {//mQueuedFrames>0说明有Surface更新的需求
        if (mRefreshPending) {
            return outDirtyRegion;
        }
 
        // Capture the old state of the layer for comparisons later
        const State& s(getDrawingState());
        const bool oldOpacity = isOpaque(s);
        sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
        
        struct Reject : public SurfaceFlingerConsumer::BufferRejecter {
            //定义Reject结构体...
        };
 
        Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
                getProducerStickyTransform() != 0);
 
        //更新纹理,得到需要的图像
        status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
                mFlinger->mPrimaryDispSync);
        //如果结果是推迟处理,发送Invalidate消息  
        if (updateResult == BufferQueue::PRESENT_LATER) {
            mFlinger->signalLayerUpdate();
            return outDirtyRegion;
        }
 
        { // Autolock scope
            Mutex::Autolock lock(mQueueItemLock);
            mQueueItems.removeAt(0);
        }
 
        //减少mQueuedFrames的值
        if (android_atomic_dec(&mQueuedFrames) > 1) {
            //如果还有更多frame需要处理,要发消息  
            mFlinger->signalLayerUpdate();
        }
 
        if (updateResult != NO_ERROR) {
            recomputeVisibleRegions = true;
            return outDirtyRegion;
        }
 
        //更新mActiveBuffer,得到现在需要输出的图像数据
        mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer();
        if (mActiveBuffer == NULL) {
            return outDirtyRegion;//出错
        }
 
        mRefreshPending = true;
        mFrameLatencyNeeded = true;
        //下面根据各种情况是否重新计算更新区域
        if (oldActiveBuffer == NULL) {
            recomputeVisibleRegions = true;
        }
 
        Rect crop(mSurfaceFlingerConsumer->getCurrentCrop());
        const uint32_t transform(mSurfaceFlingerConsumer->getCurrentTransform());
        const uint32_t scalingMode(mSurfaceFlingerConsumer->getCurrentScalingMode());
        if ((crop != mCurrentCrop) ||
            (transform != mCurrentTransform) ||
            (scalingMode != mCurrentScalingMode))
        {
            mCurrentCrop = crop;
            mCurrentTransform = transform;
            mCurrentScalingMode = scalingMode;
            recomputeVisibleRegions = true;
        }
 
        if (oldActiveBuffer != NULL) {
            uint32_t bufWidth  = mActiveBuffer->getWidth();
            uint32_t bufHeight = mActiveBuffer->getHeight();
            if (bufWidth != uint32_t(oldActiveBuffer->width) ||
                bufHeight != uint32_t(oldActiveBuffer->height)) {
                recomputeVisibleRegions = true;
            }
        }
 
        mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
        if (oldOpacity != isOpaque(s)) {
            recomputeVisibleRegions = true;
        }
 
        Region dirtyRegion(Rect(s.active.w, s.active.h));
        outDirtyRegion = (s.transform.transform(dirtyRegion));
    }
    return outDirtyRegion;
}

latchBuffer函数调用updateTextImage来得到需要的图像纹理。这里参数r是Reject对象,其作用是判断在缓冲区的尺寸是否符合要求。updateTextImage的代码实现如下:

status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter)
{
    ATRACE_CALL();
    ALOGV("updateTexImage");
    Mutex::Autolock lock(mMutex);

    if (mAbandoned) {
        ALOGE("updateTexImage: GLConsumer is abandoned!");
        return NO_INIT;
    }

    // Make sure the EGL state is the same as in previous calls.
    status_t err = checkAndUpdateEglStateLocked();
    if (err != NO_ERROR) {
        return err;
    }

    BufferQueue::BufferItem item;

    // 1、Acquire the next buffer.
    // In asynchronous mode the list is guaranteed to be one buffer
    // deep, while in synchronous mode we use the oldest buffer.
    err = acquireBufferLocked(&item, computeExpectedPresent());
    if (err != NO_ERROR) {
        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
            err = NO_ERROR;
        } else if (err == BufferQueue::PRESENT_LATER) {
            // return the error, without logging
        } else {
            ALOGE("updateTexImage: acquire failed: %s (%d)",
                strerror(-err), err);
        }
        return err;
    }


    // We call the rejecter here, in case the caller has a reason to
    // not accept this buffer.  This is used by SurfaceFlinger to
    // reject buffers which have the wrong size
    int buf = item.mBuf;
    if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
        releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, EGL_NO_SYNC_KHR);
        return NO_ERROR;
    }

    //2、 Release the previous buffer.
    err = updateAndReleaseLocked(item);
    if (err != NO_ERROR) {
        return err;
    }

    if (!SyncFeatures::getInstance().useNativeFenceSync()) {
        // Bind the new buffer to the GL texture.
        //
        // Older devices require the "implicit" synchronization provided
        // by glEGLImageTargetTexture2DOES, which this method calls.  Newer
        // devices will either call this in Layer::onDraw, or (if it's not
        // a GL-composited layer) not at all.
        //3、
        err = bindTextureImageLocked();
    }

    return err;
}

在看 bindTextureImageLocked 之前,先看看acquireBufferLocked、releaseBufferLocked两函数:

但是在这之前还要了解一下Android 的buffer状态图画 :

APP 作为我们的生产者,他会从FREE状态里面的buffer,dequeue 一个出来,向其填充数据,但APP 调用surface->unlock,的时候,DEQUEUED状态的buffer会变成QUEUED转态的buffer,当执行到updateTextImage 函数时,我们的消费者,会从QUEUED状态里面的buffer acquire 一个出来,变成ACQUIRED状态,当消费完之后会调用releaseBufferLocked,将ACQUIRED转态的buffer release掉,又变回FREE状态。下次生产者又可以拿来用了。

PS 注: QueueBuffer 的使用过程的4种状态:

( 1)FREE表示该Buffer没有被使用,且内容为空

( 2 ) DEQUEUED表示该Buffer正在被内容生产者绘制

( 3 ) QUEUED表示该Buffer已经被绘制了内容,放入BufferQueue,等待被显示(或者下一步处理)

( 4 ) ACQUIRED表示该Buffer正在被消费者拿去做显示(或者下一步处理)

 

acquireBufferLocked 会调用到 ConsumerBase::acquireBufferLocked  函数如下:

status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item,
        nsecs_t presentWhen) {
    status_t err = mConsumer->acquireBuffer(item, presentWhen);
    if (err != NO_ERROR) {
        return err;
    }

    if (item->mGraphicBuffer != NULL) {
        mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer;
    }

    mSlots[item->mBuf].mFrameNumber = item->mFrameNumber;
    mSlots[item->mBuf].mFence = item->mFence;

    CB_LOGV("acquireBufferLocked: -> slot=%d/%" PRIu64,
            item->mBuf, item->mFrameNumber);

    return OK;
}

可以看见 这个函数里面调用了 mConsumer->acquireBuffer(item, presentWhen); mConsumer 是谁?mConsumer 就是 BufferQueueConsumer 类的对象,怎么来的看下:

void Layer::onFirstRef() {
    // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
    sp<IGraphicBufferProducer> producer;
    sp<IGraphicBufferConsumer> consumer;
    BufferQueue::createBufferQueue(&producer, &consumer);
    mProducer = new MonitoredProducer(producer, mFlinger);
    mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName);
    mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
    mSurfaceFlingerConsumer->setContentsChangedListener(this);
    mSurfaceFlingerConsumer->setName(mName);

#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
#warning "disabling triple buffering"
    mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
#else
    mSurfaceFlingerConsumer->setDefaultMaxBufferCount(3);
#endif

    const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
    updateTransformHint(hw);
}

即是在创建 SurfaceControl 的时候,触发 Layer::onFirstRef ()时,mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName);传进去的consumer,最终复制给了mConsumer,所以mConsumer 就是BufferQueueConsumer。所以mConsumerr->acquireBuffer(item, presentWhen)最终会调用到BufferQueueConsumer::acquireBuffer()

status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
        nsecs_t expectedPresent) {
    ATRACE_CALL();
    Mutex::Autolock lock(mCore->mMutex);

    // Check that the consumer doesn't currently have the maximum number of
    // buffers acquired. We allow the max buffer count to be exceeded by one
    // buffer so that the consumer can successfully set up the newly acquired
    // buffer before releasing the old one.
    int numAcquiredBuffers = 0;
    for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
        if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) {
            ++numAcquiredBuffers;
        }
    }
    if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
        BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)",
                numAcquiredBuffers, mCore->mMaxAcquiredBufferCount);
        return INVALID_OPERATION;
    }

    // Check if the queue is empty.
    // In asynchronous mode the list is guaranteed to be one buffer deep,
    // while in synchronous mode we use the oldest buffer.
    if (mCore->mQueue.empty()) {
        return NO_BUFFER_AVAILABLE;
    }

    BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());

    // If expectedPresent is specified, we may not want to return a buffer yet.
    // If it's specified and there's more than one buffer queued, we may want
    // to drop a buffer.
    if (expectedPresent != 0) {
        const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second

        // The 'expectedPresent' argument indicates when the buffer is expected
        // to be presented on-screen. If the buffer's desired present time is
        // earlier (less) than expectedPresent -- meaning it will be displayed
        // on time or possibly late if we show it as soon as possible -- we
        // acquire and return it. If we don't want to display it until after the
        // expectedPresent time, we return PRESENT_LATER without acquiring it.
        //
        // To be safe, we don't defer acquisition if expectedPresent is more
        // than one second in the future beyond the desired present time
        // (i.e., we'd be holding the buffer for a long time).
        //
        // NOTE: Code assumes monotonic time values from the system clock
        // are positive.

        // Start by checking to see if we can drop frames. We skip this check if
        // the timestamps are being auto-generated by Surface. If the app isn't
        // generating timestamps explicitly, it probably doesn't want frames to
        // be discarded based on them.
        while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
            // If entry[1] is timely, drop entry[0] (and repeat). We apply an
            // additional criterion here: we only drop the earlier buffer if our
            // desiredPresent falls within +/- 1 second of the expected present.
            // Otherwise, bogus desiredPresent times (e.g., 0 or a small
            // relative timestamp), which normally mean "ignore the timestamp
            // and acquire immediately", would cause us to drop frames.
            //
            // We may want to add an additional criterion: don't drop the
            // earlier buffer if entry[1]'s fence hasn't signaled yet.
            const BufferItem& bufferItem(mCore->mQueue[1]);
            nsecs_t desiredPresent = bufferItem.mTimestamp;
            if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
                    desiredPresent > expectedPresent) {
                // This buffer is set to display in the near future, or
                // desiredPresent is garbage. Either way we don't want to drop
                // the previous buffer just to get this on the screen sooner.
                BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%"
                        PRId64 " (%" PRId64 ") now=%" PRId64,
                        desiredPresent, expectedPresent,
                        desiredPresent - expectedPresent,
                        systemTime(CLOCK_MONOTONIC));
                break;
            }

            BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64
                    " size=%zu",
                    desiredPresent, expectedPresent, mCore->mQueue.size());
            if (mCore->stillTracking(front)) {
                // Front buffer is still in mSlots, so mark the slot as free
                mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
            }
            mCore->mQueue.erase(front);
            front = mCore->mQueue.begin();
        }

        // See if the front buffer is due
        nsecs_t desiredPresent = front->mTimestamp;
        if (desiredPresent > expectedPresent &&
                desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) {
            BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64
                    " (%" PRId64 ") now=%" PRId64,
                    desiredPresent, expectedPresent,
                    desiredPresent - expectedPresent,
                    systemTime(CLOCK_MONOTONIC));
            return PRESENT_LATER;
        }

        BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " "
                "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent,
                desiredPresent - expectedPresent,
                systemTime(CLOCK_MONOTONIC));
    }

    int slot = front->mSlot;
    *outBuffer = *front;
    ATRACE_BUFFER_INDEX(slot);

    BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }",
            slot, front->mFrameNumber, front->mGraphicBuffer->handle);
    // If the front buffer is still being tracked, update its slot state
    if (mCore->stillTracking(front)) {
        mSlots[slot].mAcquireCalled = true;
        mSlots[slot].mNeedsCleanupOnRelease = false;
        mSlots[slot].mBufferState = BufferSlot::ACQUIRED;
        mSlots[slot].mFence = Fence::NO_FENCE;
    }

    // If the buffer has previously been acquired by the consumer, set
    // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer
    // on the consumer side
    if (outBuffer->mAcquireCalled) {
        outBuffer->mGraphicBuffer = NULL;
    }

    mCore->mQueue.erase(front);

    // We might have freed a slot while dropping old buffers, or the producer
    // may be blocked waiting for the number of buffers in the queue to
    // decrease.
    mCore->mDequeueCondition.broadcast();

    ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());

    return NO_ERROR;
}

其实就是从mCore->mQueue 队列中取出第一个构造好的buffer。

同理如此分析releaseBufferLocked 函数。

回过头看一下 bindTextureImageLocked函数 : 作用就是将新的缓冲区绑定到GL纹理,OpenGL 相关了。

status_t GLConsumer::bindTextureImageLocked() {
        ............

        glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);

        ..........
    return doGLFenceWaitLocked();

}

 

Region 了解

对于我们桌面上的图像,他是按照Layer 一层一层的铺上的,若是Layer 的Z值比较到,那么他就越在其他Layer的上层。

对于个每一个Layer 都有透明度的概念:

①、opaque:不透明,如果这个layer的某个区域设置的是不透明,那么这个Layer层的下面的Layer 就不会被看见。

②、transparent : 全透明,可以完全看见下面层的Layer。

③、translucent : 半透明,还是可以看见下面层的Layer。

在程序中,通过Region 结构体来表述透明度。

Region  由一系列的Rect(矩形)组成,这些矩形从上到下,从左到右排列出来,并且各个矩形的Y轴坐标相同(对于Y轴坐标相同的矩形X轴无交叉)或者无交叉。

Span :一组Rect ,Y轴一样,X轴无交叉。

Region定义的文件:frameworks\native\include\ui\Region.h ,里面有一个 Vector<Rect> mStorage; 成员变量。mStorage的最后一项表示边界

  1. 如果Region只是一个简单的矩形区域,则mStorage只包含一个Rect类型的元素。
  2. 如果Region中包含多个矩形区域,则mStorage只包含多个Rect类型的元素+最后元素(这块区域的边界)。

 

 

 

3、 signalRefresh();

void SurfaceFlinger::signalRefresh() {
    mEventQueue.refresh();
}

导致 case MessageQueue::REFRESH:下的 handleMessageRefresh();被调用。

void SurfaceFlinger::handleMessageRefresh() {
    ATRACE_CALL();
    preComposition(); //关键点1 合成前预处理
    rebuildLayerStacks();//关键点2 计算可见区域,主要依据:z-order大的覆盖有重叠区域z-order小的
    //关键点3 下面几个方法都是页面合成相关
    setUpHWComposer();
    doDebugFlashRegions();
    doComposition();//关键点4 合成所有层的图像, 经过这一步后,就显示新的内容了
    postComposition();//合成之后的工作
}

handleMessageRefresh

在handleMessageRefresh 函数里面,做的主要的工作是:

①计算各个Layer的显示区域

②合成并且显示,可以通过OpenGL的方式把每个layer的可视区域在一个内存里面描述出来;也可以通过硬件 HWComposer合成出来。

 

 ① preComposition():

处理一些标志位。

② rebuildLayerStacks():

显然rebuildLayerStacks()函数就是来处理各个Layer的显示区域。

在分析之前需要明确个基本概念:

  1. dirtyRegion:表示该区域是需要被刷新的。
  2. opaqueRegion:表示不透明区域。
  3. transparentRegion:表示完全透明区域。
  4. translucentRegion:表示半透明区域。

rebuildLayerStacks主要是做两件事:

  1. 重建每个显示设备的可见layer对象的列表。layer按照Z序排列,但每个Layer都有 透明区、不透明区、半透明区即下面的Layer某些区域也是有机会显示的
  2. 对每个显示设备,先计算和显示设备相同的layerStack值的layer对象在显示设备上的可见区域,然后将可见区域和显示设备的窗口有交集的layer组成一个新的列表,最后把这个列表设置到显示设备对象中。
void SurfaceFlinger::rebuildLayerStacks() {
    // rebuild the visible layer list per screen
    if (CC_UNLIKELY(mVisibleRegionsDirty)) {
        ATRACE_CALL();
        mVisibleRegionsDirty = false;
        invalidateHwcGeometry();

        const LayerVector& layers(mDrawingState.layersSortedByZ);
        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
            Region opaqueRegion;
            Region dirtyRegion;
            Vector< sp<Layer> > layersSortedByZ;
            const sp<DisplayDevice>& hw(mDisplays[dpy]);
            const Transform& tr(hw->getTransform());
            const Rect bounds(hw->getBounds());
            if (hw->canDraw()) {
                SurfaceFlinger::computeVisibleRegions(layers,
                        hw->getLayerStack(), dirtyRegion, opaqueRegion);//计算每个Layer的可见区域,确定设备需要重新绘制的区域

                const size_t count = layers.size();
                for (size_t i=0 ; i<count ; i++) {
                    const sp<Layer>& layer(layers[i]);
                    const Layer::State& s(layer->getDrawingState());
                    if (s.layerStack == hw->getLayerStack()) {//只需要和显示设备的layerStacek相同的Layer
                        Region drawRegion(tr.transform(
                                layer->visibleNonTransparentRegion));
                        drawRegion.andSelf(bounds);
                        if (!drawRegion.isEmpty()) {
                            //如果Layer的显示区域和显示设备的窗口有交集
                            //把Layer加入到列表中
                            layersSortedByZ.add(layer);
                        }
                    }
                }
            }
            hw->setVisibleLayersSortedByZ(layersSortedByZ);//设置显示设备的可见Layer列表
            hw->undefinedRegion.set(bounds);
            hw->undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
            hw->dirtyRegion.orSelf(dirtyRegion);
        }
    }
}

SurfaceFlinger::computeVisibleRegions()比较核心重要,他的作用是记录各个Layer 的可视区域、被遮盖区域,并记录在layer中,汇总dirtyRegion, opaqueRegion形参中,即总的dirtyRegion 区域和总的opaqueRegion。最后回到rebuildLayerStacks,把得到的这些信息set到hw 对象里面去,用于接下来的合成。

先浏览一下computeVisibleRegions 函数吧:

void SurfaceFlinger::computeVisibleRegions(
        const LayerVector& currentLayers, uint32_t layerStack,
        Region& outDirtyRegion, Region& outOpaqueRegion)
{
    Region aboveOpaqueLayers;//当前层之上累计的不透明区域
    Region aboveCoveredLayers;//当前层之上累计的被覆盖区域,不透明+半透明
    Region dirty;
    outDirtyRegion.clear();总值
 
    size_t i = currentLayers.size();//最上层layer的索引
    while (i--) {//从Z轴 最上面的layer开始处理,由上到下
        const sp<Layer>& layer = currentLayers[i];
        const Layer::State& s(layer->getDrawingState());
        // 只计算和layerstack相同的layer,其他忽略
        if (s.layerStack != layerStack)
            continue;
 
        Region opaqueRegion;        //不透明区域
        Region visibleRegion;       //可见区域,不透明区域+半透明区域
        Region coveredRegion;       //覆盖区域,可见区域覆盖的地方
        Region transparentRegion;   //完全透明区域
        //stage1-start 得到当前Layer的原始可视区域 和 opaque区域
        // handle hidden surfaces by setting the visible region to empty
        if (CC_LIKELY(layer->isVisible())) {
            const bool translucent = !layer->isOpaque(s);
            Rect bounds(s.transform.transform(layer->computeBounds()));
            visibleRegion.set(bounds);
            if (!visibleRegion.isEmpty()) {
                // Remove the transparent area from the visible region
                if (translucent) {//计算透明区域
                    const Transform tr(s.transform);
                    if (tr.transformed()) {
                        if (tr.preserveRects()) {
                            // transform the transparent region
                            transparentRegion = tr.transform(s.activeTransparentRegion);
                        } else {
                            // transformation too complex, can't do the
                            // transparent region optimization.
                            transparentRegion.clear();
                        }
                    } else {
                        transparentRegion = s.activeTransparentRegion;
                    }
                }
 
                // 计算不透明区域
                const int32_t layerOrientation = s.transform.getOrientation();
                if (s.alpha==255 && !translucent &&
                        ((layerOrientation & Transform::ROT_INVALID) == false)) {
                    opaqueRegion = visibleRegion;
                }
            }
        }
        //stage1-end
 
        //当前Layer被遮盖区域:上层的覆盖区 和 layer所在区域的 交集
        coveredRegion = aboveCoveredLayers.intersect(visibleRegion);
 
        // 扩大覆盖区域,为下次循环、即下层计算做准备
        aboveCoveredLayers.orSelf(visibleRegion);
 
        //可见区域 = 抠掉上层的不透明区域
        visibleRegion.subtractSelf(aboveOpaqueLayers);
 
        // 计算需要重绘的区域
        if (layer->contentDirty) {
            //内容变了,重绘整个可见区域
            dirty = visibleRegion;
            //以前的看见区域也要加进来,因为以前的内容需要抹掉
            dirty.orSelf(layer->visibleRegion);
            layer->contentDirty = false;
        } else {
            //暴露区域 = 可见区域-被覆盖区域
            const Region newExposed = visibleRegion - coveredRegion;
            const Region oldVisibleRegion = layer->visibleRegion;
            const Region oldCoveredRegion = layer->coveredRegion;
            const Region oldExposed = oldVisibleRegion - oldCoveredRegion;
            dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed);
        }
        
        //layer的重绘区域 = 抠掉上层的不透明区域
        dirty.subtractSelf(aboveOpaqueLayers);
 
        //累计每层需要重绘的区域
        outDirtyRegion.orSelf(dirty);
 
        //更新aboveOpaqueLayers,为下层layer绘制做准备
        aboveOpaqueLayers.orSelf(opaqueRegion);
 
        //设置layer对象的区域
        layer->setVisibleRegion(visibleRegion);
        layer->setCoveredRegion(coveredRegion);
        //设置可见的非透明区域
        layer->setVisibleNonTransparentRegion(
                visibleRegion.subtract(transparentRegion));
    }
 
    outOpaqueRegion = aboveOpaqueLayers;
}

总结下computeVisibleRegions的逻辑如下:

先计算每个layer在设备上的可见区域visibleRegion(不透明区域 + 半透明区域)。计算方法:整个Layer的区域-上层所有不透明区域aboveOpaqueLayers。而上层所有不透明区域的值 是一个逐层累积的过程,每层都把自己的不透明区域累加到aboveOpaqueLayers中。

每层的不透明区域的计算方法:如果layer的alpha值=255,并且layer的isOpaque = true,则本层的不透明区域 == layer所在区域。否则为0。这样一层层计算下来,就很容易得到每层的可见区域大小了。

这里以下图为例,解读下computeVisibleRegions这段逻辑:

假设有三个Layer,按照Z值从大到小,依次是Layer1->Layer2->Layer3,最后按照computeVisibleRegions的规则来合成Layer。有了这个图,看这段逻辑 便会更加直观。同时理解这段逻辑 最好的方法是将3个Layer带入到computeVisibleRegions方法中。

 

③setUpHWComposer

先不用管这个,这个这函数是硬件合成图像的(HWComposer),里面会有判断是否支持HWC,我们假设不支持,完全走egl ,gpu 合成,所以直接看doComposition函数。

④doComposition

在分析这个函数之前,先了解一下 DisplayDevice 类的作用。

先看一下两张图:

第一张图,表示我们的应用程序,获取surface,向surface请求buffer,这个buffer是android匿名内存里面分配出来的,这些buffer被surface这边的成员变量mSlots 管理着,当应用这边调用unlockAndPost 函数,提交已经绘制图像buffer以后,layer会通知surfaceflinger进程去处理新添加的buffer。surfaceflinger 经过文章前面一些流程处理后,就会把合成的buffer,提交给framebuffer,framebuffer是硬件分配的buffer,他们他们也是被surface类管理着,那么DisplayDevice的作用是啥呢?DisplayDevice类似于我们的应用进程,管理的是帧他可以请求硬件dequeuebuffer、queuebuffer,即lock、unlock的过程。

  1. 应用端的Buffer是向Ashmem申请的;DisplayDevice端的Buffer是向FrameBuffer申请的
  2. 应用端的Buffer是用来填充的;DisplayDevice端的Buffer是用来推给Framebuffer 渲染的

看一下DisplayDevice的创建过程:

DisplayDevice的创建过程在SurfaceFlinger::init()里面:

void SurfaceFlinger::init() {
    //...
    // 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) {
            // All non-virtual displays are currently considered secure.
            bool isSecure = true;
            createBuiltinDisplayLocked(type);
            wp<IBinder> token = mBuiltinDisplays[i];
            //BufferQueue相关
            sp<IGraphicBufferProducer> producer;
            sp<IGraphicBufferConsumer> consumer;
            BufferQueue::createBufferQueue(&producer, &consumer,
                    new GraphicBufferAlloc());
            //关键点1:FramebufferSurface创建,定位为 消费者身份
            sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
                    consumer);
            int32_t hwcId = allocateHwcDisplayId(type);
            //关键点2:DisplayDevice创建,定位为 生产者身份
            sp<DisplayDevice> hw = new DisplayDevice(this,
                    type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
                    fbs, producer,
                    mRenderEngine->getEGLConfig());
            if (i > DisplayDevice::DISPLAY_PRIMARY) {
                hw->setPowerMode(HWC_POWER_MODE_NORMAL);
            }
            mDisplays.add(token, hw);
        }
    }
    //...
    // start boot animation
    startBootAnim();
}

FramebufferSurface构造函数实现如下:

FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp,
        const sp<IGraphicBufferConsumer>& consumer) :
    ConsumerBase(consumer),
    mDisplayType(disp),
    mCurrentBufferSlot(-1),
    mCurrentBuffer(0),
    mHwc(hwc)
{
    mName = "FramebufferSurface";
    mConsumer->setConsumerName(mName);
    /*这里设置了标志位GRALLOC_USAGE_HW_FB,借此参数分辨
    向Ashmem申请->APP;向Framebuffer申请->DisplayDevice
    */
    mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
                                       GRALLOC_USAGE_HW_RENDER |
                                       GRALLOC_USAGE_HW_COMPOSER);
    mConsumer->setDefaultBufferFormat(mHwc.getFormat(disp));
    mConsumer->setDefaultBufferSize(mHwc.getWidth(disp),  mHwc.getHeight(disp));
    mConsumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS);
}

通过setConsumerUsageBits 函数,可以设置一个标志位,如果,表示向匿名共享内存申请buffer,为GRALLOC_USAGE_HW_FB,表示向显现驱动程序申请Framebuffer。

DisplayDevice的构造函数实现如下:

DisplayDevice::DisplayDevice(
        const sp<SurfaceFlinger>& flinger,
        DisplayType type,
        //...各种初始化
{
    //创建surface对象
    mNativeWindow = new Surface(producer, false);
    ANativeWindow* const window = mNativeWindow.get();
 
    //创建OpenGLES 使用的surface对象
    EGLSurface surface;
    EGLint w, h;
    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    if (config == EGL_NO_CONFIG) {
        config = RenderEngine::chooseEglConfig(display, format);
    }
    surface = eglCreateWindowSurface(display, config, window, NULL);
    eglQuerySurface(display, surface, EGL_WIDTH,  &mDisplayWidth);
    eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight);
 
    if (mType >= DisplayDevice::DISPLAY_VIRTUAL)
        window->setSwapInterval(window, 0);//虚拟设备不支持 图像合成
 
    mConfig = config;
    mDisplay = display;
    mSurface = surface;
    mFormat  = format;
    mPageFlipCount = 0;
    mViewport.makeInvalid();
    mFrame.makeInvalid();
 
    //虚拟设备的屏幕 默认不关闭
    mPowerMode = (mType >= DisplayDevice::DISPLAY_VIRTUAL) ?
                  HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
 
    // Name the display.  The name will be replaced shortly if the display
    // was created with createDisplay().
    switch (mType) {
        case DISPLAY_PRIMARY:
            mDisplayName = "Built-in Screen";
            break;
        case DISPLAY_EXTERNAL:
            mDisplayName = "HDMI Screen";
            break;
        default:
            mDisplayName = "Virtual Screen";    // e.g. Overlay #n
            break;
    }
 
    // initialize the display orientation transform.
    setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
}

该构造函数主要是 创建了Surface,也就是一个NativeWindow。

这里看下 surface的构造函数,代码如下:

Surface::Surface(
        const sp<IGraphicBufferProducer>& bufferProducer,
        bool controlledByApp)
    : mGraphicBufferProducer(bufferProducer)
{
    // Initialize the ANativeWindow function pointers.
    ANativeWindow::setSwapInterval  = hook_setSwapInterval;
    ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
    ANativeWindow::cancelBuffer     = hook_cancelBuffer;
    ANativeWindow::queueBuffer      = hook_queueBuffer;
    ANativeWindow::query            = hook_query;
    ANativeWindow::perform          = hook_perform;
    //...
}

这里对其中的一个hook_queueBuffer进行分析,代码如下:

int Surface::hook_queueBuffer(ANativeWindow* window,
        ANativeWindowBuffer* buffer, int fenceFd) {
    Surface* c = getSelf(window);
    return c->queueBuffer(buffer, fenceFd);
}

最后是调用回了Surface的queueBuffer方法,其他几个hook方法也是类似的。即NativeWindow 和Surface访问的方法是一样的。

同时通过上面的分析得出Buffer的流程:Surface->BufferQueue->FramebufferSurface->HWComposer->Gralloc->显示设备Framebuffer.

 

 

最后在看一下doComposition 的函数处理内容:

这个UML图中,我们看出来在doComposeSurfaces函数里面最后会调用 layer->draw(hw, clip)进而开始调用OpenGL的接口开始绘制合成图像了。完了之后,回到doDisplayComposition函数,调用hw->swapBuffers(getHwComposer()),进行framebuffer的切换,即把准备好的framebuffer和正在显示器上显示的buffer进行交换,显示器就显示刚刚合成的新画面。

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

android 使用SurfaceFlinger 服务的流程分析,基于4.4(三)----图像的输出过程 的相关文章

  • 快手出海求生

    配图来自Canva可画 随着八月接近尾声 众多上市公司的中期成绩单纷纷出炉 这其中就有视频社区B站 游戏直播斗鱼等内容平台的财报 不过 从其披露的财报中可以看出 如今内容平台的发展都不容乐观 而作为 短视频双雄之一 的快手近期交出的答卷中
  • WebSphere之wasprofile.sh使用

    概要文件 profile 6 0版本以后才有profile 目的是将用户数据和was本身的文件分开 这样可以定义多个profile 每个profile相当于一个用户 相当于提供了多用户的支持 profile的命令说明 新建 wasprofi
  • vue-echarts饼图/柱状图点击事件

    在实际的项目开发中 我们通常会用到Echarts来对数据进行展示 有时候需要用到Echarts的点击事件 增加系统的交互性 一般是点击Echarts图像的具体项来跳转路由并携带参数 当然也可以根据具体需求来做其他的业务逻辑 下面就Echar
  • UGUI—事件,iTween插件

    预计两三天内 做2048游戏和一款自己编写的方块小游戏 期待一下喽 每日一句 游戏制作是声色张扬下我欲盖弥彰的温柔理想 目录 UGUI事件 事件注册 通过编辑器绑定方法 AddListener 实现接口 自定义框架 iTween动画库 自动
  • Vue+Element组件封装

    使用element经常需要用表格展示数据 对表格内容进行分页以及搜索都是比较常见的需求 于是想到了对element进行二次封装 主要涉及的组件有el table el dropdown 控制每页展示条目数 el pagination tab
  • 入坑机器学习:四,单变量线性回归

    开始我们机器学习的第一个算法 还是借用吴老师的例子 这个例子是预测住房价格的 我们要使用一个数据集 数据集包含俄勒冈州波特兰市的住房价格 在这里 我要根据不同房屋尺寸所售出的价格 画出我的数据集 比方说 如果你朋友的房子是 1250 平方尺
  • 面单扫描成本从2元降到1毛,薄利的物流业怎么靠技术赚钱?

    政策春风 又将加速 数字经济 的列车 在未来5 10年间 千行百业将在数字化 智能化的浪潮下重新做一遍 我们愿意成为这一历史阶段的观察者 记录者 探索 数智化 栏目将通过对消费 汽车 制造业 农业 服务业等千行百业的数字化 智能化落地案例
  • 互联网摸鱼日报(2023-03-08)

    互联网摸鱼日报 2023 03 08 InfoQ 热门话题 两会热点讨论 如何帮助中小企业在数字化时代不掉队 转型调研 鼎新汇 企业行 第一站 走进中国联通软件研究院 为什么你的大多数监控策略都失败了 ChatGPT等AI很强大 但为什么还
  • python是一门面向过程的语言_day5-python之面向过程编程

    import os def init func def wrapper args kwargs g func args kwargs next g return g return wrapper 第一阶段 找到所有文件的绝对路径 init
  • 腾讯云轻量应用服务器使用教程_创建_连接_建站

    腾讯云轻量应用服务器怎么使用 轻量应用服务器使用包括快速创建轻量服务器 轻量服务器远程连接 使用轻量应用服务器搭建网站教程 轻量服务器开通端口教程等 腾讯云服务器网整理了关于腾讯云轻量应用服务器的使用教程 目录 一 创建轻量应用服务器 二
  • 71-C语言-逆序拼接两个字符串

    问题 拼接字符串 拼接的那个字符串 需要先拼接 再连接 思路 两个字符数组 先创建出来并赋值 计算字符串的长度 随后弄两个指针 在一个for循环中 进行添加赋值 第一个数组从字母串末尾开始 然后让另一个数组的末尾处值给值到第一个数组中 随后
  • iperf使用方法windows_iperf3使用方法详解

    iperf3是一款带宽测试工具 它支持调节各种参数 比如通信协议 数据包个数 发送持续时间 测试完会报告网络带宽 丢包率和其他参数 小广告 欢迎喜欢网络技术的朋友加我微信 xfiles sky 一起学习 一 安装 操作系统 Ubuntu20
  • 常用的边缘算子

    边缘算子 边缘算子 sobel Roberts Prewitt Canny Laplacian 对比 边缘算子 参考链接 https blog csdn net yato0514 article details 82051790 图像方面的
  • 【PS CS6】替换证件照背景色

    参考链接 如何用PS替换证件照的背景色 1 首先把你需要处理的证件照片在ps软件里打开 裁剪到合适的位置大小 然后CTRL J 复制一个图层 2 选中复制的图层 然后在工具栏里选择快速选择工具 3 用快速选择工具选中证件照的白色背景 这里需
  • elasticsearch批量插入数据的时候出现java.net.SocketTimeoutException: 30,000 milliseconds timeout on connection

    问题 elasticsearch每次都批量插入几万数据量 然后就会出现下列问题 看这个问题应该是配置的问题 ERROR https jsse nio 443 exec 4 2020 07 09 23 31 54 EsMiniDaansouD
  • 变分(Calculus of variations)的概念及运算规则(一)

    文章目录 1 回顾 微分的定义 2 泛函和变分概念简介 2 1 泛函概念简介 2 2 变分概念简介 3 变分的运算法则简介 4 变分法详述 4 1 历史 4 2 极值 5 变分的运算法则详述 5 1 定义 5 1 1 泛函导数 5 1 2
  • feign使用get请求无法传递对象类型参数解决

    SpringQueryMap是微服务之间调用 使用openfeign通过get请求方式来处理 多入参 也就是通过实体来传参 情况的注解 多用于restful风格方式 作用 SpringQueryMap 简单来说就是将实体转化为表单数据 比如
  • 主析取范式和主合取范式

    主析取范式 小项 是n个命题变元的合取式 其中每个变元必出现且仅出现一次 以本身或否定形式 称这个合取式为小项 例 含有两个变元的小项 P Q P Q P Q P Q 若有n个变元 则有2的n次方个小项 小项编码 含有n个变元的小项的角标用
  • JAVA递归查询根据当前节点查询所有子节点

    public List

随机推荐

  • 数据库从入门到精通01

    文章目录 数据库应用 概念 什么是数据库 关系型和非关系型 关系型数据库 Mysql数据库 MySQL数据存放在哪里 MySQL服务端 MySQL客户端1 DOS窗口 MySQL客户端2 可视化工具 数据库的结构 数据库结构 SQL语句 定
  • python实用脚本(六)—— pandas库的使用(生成、读取表格)

    本期主题 python的pandas使用 往期链接 python实用脚本 一 批量修改目标文件夹下的文件名 python实用脚本 二 使用xlrd读取excel python实用脚本 三 通过有道智云API实现翻译 python实用脚本 四
  • 2021年全国职业院校技能大赛 “大数据技术与应用”—模拟赛题(一)

    2021年全国职业院校技能大赛 大数据技术与应用 模拟赛题 一 文章适合了解大数据技术与应用技能大赛 赛题 文章在编写过程中难免有疏漏和错误 欢迎大佬指出文章的不足之处 更多内容请点进 Lino White 查看 未来的世界充满着各式各样的
  • vscode的“安装”、“软件中文化”、“代码格式化”和“前端边编程边看到效果”的过程设置方法

    本文主要用来对vscode进行基础设置 通篇看起来偏过程化 最好从头到尾一步一步跟着设置 目录 一 安装vscode 二 安装 Chinese 插件 使软件中文化 三 安装软件主题 使软件界面个性化 四 将一个文件目录作为项目目录打开 五
  • Matlab:尝试将 SCRIPT XXX 作为函数执行的解决方案

    Matlab 尝试将 SCRIPT XXX 作为函数执行的解决方案 最近在做图像处理小实验的过程中遇到了无比沙雕的情况 被自己佛了 最近真的智商不在线 或者没在线过 先描述一下问题 在Matlab中调用直方图均衡化函数histeq 但是出现
  • 进程、线程相关基础理论总结

    进程 线程相关基础理论 一 进程与线程的区别 1 进程是指一个程序在计算机中的一次运行 它是资源分配的最小单位 2 线程是进程中调度执行的最小单位 3 进程有独立的内存空间 线程没有独立的内存空间 它必须运行在进程中 4 线程之间通信更方便
  • Runnable可以实现资源共享但Thread不能实现资源共享的原因

    转自 http blog csdn net javaniceyou article details 6859305 线程的两种实现方式 通过实现Runnable接口的线程方式可以实现资源的共享 而继承Thread则不可以 原因何在 先看下面
  • 华为OD2023(A卷)基础题37【工单调度策略】

    工单调度策略 题目描述 当小区通信设备上报警时 系统会自动生成待处理的工单 工单调度系统需要根据不同的策略 调度外线工程师 FME 上站去修复工单对应的问题 根据与运营商签订的合同 不同严重程度的工单被处理并修复的时长要求不同 这个要求被修
  • Android OpenGL 纹理绘制图像---Native实现

    本文纹理贴图的native实现 是指指定纹理的功能放在了native中实现 其他流程和Java实现类似 在这里就不赘述了 再回头看一下指定纹理数据的方法 void glTexImage2D GLenum target GLint level
  • 剑指 Offer 29. 顺时针打印矩阵

    顺时针打印矩阵 顺时针打印矩阵 思路 题解 JAVA判断二维数组是否空 左 下 右 上四条变上的循环 思路 参考视频 题解 注意边界条件 JAVA判断二维数组是否空 1 二维数组首地址是否为空 即array null 2 二维数组是否为 即
  • 命令行svn commit时注释实现换行

    svn ci m 11111 其中 111111 就是你填写的注释 如果你想换行写 也是可以的 只要你不写后面的那个引号 你可以写一行就回车一次 最后写完了 再加上后面的引号 然后再回车 就执行提交动作了 svn ci m 11111 gt
  • flutter简单的本地草稿箱功能

    需求1 发帖退出时提示是否保存草稿 需求2 每条草稿中可以保存多张图片 最多9张 或一条视频及三十来个其它参数 需求3 每条草稿都是可以被覆盖的 可以点击删除 需求4 草稿页面可以一键清空 需求5 草稿随app删除一起没掉 看到需求第一时间
  • 剑指 Offer 04. 二维数组中的查找

    题目链接 04 二维数组中的查找 思路分析 利用右上角的数来判断减少判断行数 如果右上角的数大于target那么该列都大于 所以j 如果小于target那么改行都小于 所以i class Solution public bool findN
  • MFC之模态非模态与自定义对话框16

    1 模态非模态对话框 由于我们这里使用按下菜单栏的选项弹出对话框 所以放在框架类中使用 注意 按下选项可以使用左键按下事件或者选项对应的处理事件 我们使用后者 这点需要区分好 1 先在菜单栏添加对话框的选项 2 在资源视图添加对话框 3 添
  • 语义分割的基本网络结构

    1 编码器 编码器通常可以理解为一些列对应的卷积模块 通常由卷积层 池化层以及BN层 卷积层负责获取图像特征 池化层对图像进行下采样并且将尺度不变特征传送到下一层 而BN主要对训练图像的分布归一化 加速学习 可以理解为编码器是用来进行特征提
  • BSC链节点搭建

    BSC 节点同步教程 准备步骤 安装go环境包 GO下载地址 https golang org doc install wget c https golang org dl go1 16 3 linux amd64 tar gz O sud
  • elasticjob启动报错KeeperErrorCode = OperationTimeout

    elasticjob报错 Caused by com dangdang ddframe job reg exception RegException org apache zookeeper KeeperException Operatio
  • 在学习DNS的过程中给我的启发

    在学习DNS的过程中给我的启发 在国内 关于DNS相关的话题一直络绎不绝 比如DNS根服务器为什么中国没有 还有Anycast BGP实现负载 为什么DNS只有13个 还有DNS over HTTPS 和 DNS over TLS的优劣等等
  • 使用SqlBulkCopy大批量导入数据

    实际的开发可能会遇到数据大批量插入数据的问题 若是一条条的循环倒数效率非常低下 这个较好的解决方案 1 2 protected void Button1 Click object sender EventArgs e 3 4 5 DateT
  • android 使用SurfaceFlinger 服务的流程分析,基于4.4(三)----图像的输出过程

    经过前面两篇的介绍 现在可以分析surfaceflinger 的处理UI buffer的流程了 目录 一 onMessageReceived 1 handleMessageTransaction 2 handleMessageInvalid