Android6.0 显示系统(六) 图像的输出过程

原创 2016年10月11日 16:23:19

上篇博客分析到SurfaceFlinger收到了VSync信号后,调用了handleMessageRefresh函数,这篇博客主要就是分析这个函数,我们先看看它的代码:

void SurfaceFlinger::handleMessageRefresh() {
    ATRACE_CALL();

    static nsecs_t previousExpectedPresent = 0;
    nsecs_t expectedPresent = mPrimaryDispSync.computeNextRefresh(0);
    static bool previousFrameMissed = false;
    bool frameMissed = (expectedPresent == previousExpectedPresent);
    if (frameMissed != previousFrameMissed) {
        ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
    }
    previousFrameMissed = frameMissed;

    if (CC_UNLIKELY(mDropMissedFrames && frameMissed)) {
        // Latch buffers, but don't send anything to HWC, then signal another
        // wakeup for the next vsync
        preComposition();
        repaintEverything();
    } else {
        preComposition();
        rebuildLayerStacks();
        setUpHWComposer();
        doDebugFlashRegions();
        doComposition();
        postComposition();
    }

    previousExpectedPresent = mPrimaryDispSync.computeNextRefresh(0);
}

我们主要看下下面几个函数。

        preComposition();
        rebuildLayerStacks();
        setUpHWComposer();
        doDebugFlashRegions();
        doComposition();
        postComposition();


一、preComposition函数

我们先来看第一个函数preComposition

void SurfaceFlinger::preComposition()
{
    bool needExtraInvalidate = false;
    const LayerVector& layers(mDrawingState.layersSortedByZ);
    const size_t count = layers.size();
    for (size_t i=0 ; i<count ; i++) {
        if (layers[i]->onPreComposition()) {
            needExtraInvalidate = true;
        }
    }
    if (needExtraInvalidate) {
        signalLayerUpdate();
    }
}

上面函数先是调用了mDrawingState的layersSortedByZ来得到上次绘图的Layer层列表。并不是所有的Layer都会参与屏幕图像的绘制,因此SurfaceFlinger用state对象来记录参与绘制的Layer对象。

记得在之前的博客,我们分析过createLayer函数来创建Layer,创建之后会调用addClientLayer函数。

status_t SurfaceFlinger::createLayer(
        const String8& name,
        const sp<Client>& client,
        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp)
{
    //ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string());
    if (int32_t(w|h) < 0) {
        ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",
                int(w), int(h));
        return BAD_VALUE;
    }

    status_t result = NO_ERROR;

    sp<Layer> layer;

    switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
        case ISurfaceComposerClient::eFXSurfaceNormal:
            result = createNormalLayer(client,
                    name, w, h, flags, format,
                    handle, gbp, &layer);
            break;
        case ISurfaceComposerClient::eFXSurfaceDim:
            result = createDimLayer(client,
                    name, w, h, flags,
                    handle, gbp, &layer);
            break;
        default:
            result = BAD_VALUE;
            break;
    }

    if (result != NO_ERROR) {
        return result;
    }

    result = addClientLayer(client, *handle, *gbp, layer);
    if (result != NO_ERROR) {
        return result;
    }

    setTransactionFlags(eTransactionNeeded);
    return result;
}

我们来看下addClientLayer函数,这里会把Layer对象放在mCurrentState的layersSortedByZ对象中。而mDrawingState和mCurrentState什么关系呢?在后面我们会介绍,mDrawingState代表上一次绘图时的状态,处理完之后会把mCurrentState赋给mDrawingState。

status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
        const sp<IBinder>& handle,
        const sp<IGraphicBufferProducer>& gbc,
        const sp<Layer>& lbc)
{
    // add this layer to the current state list
    {
        Mutex::Autolock _l(mStateLock);
        if (mCurrentState.layersSortedByZ.size() >= MAX_LAYERS) {
            return NO_MEMORY;
        }
        mCurrentState.layersSortedByZ.add(lbc);
        mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
    }

    // attach this layer to the client
    client->attachLayer(handle, lbc);

    return NO_ERROR;
}

回到preComposition函数,遍历所有的Layer对象,调用其onPreComposition函数来检测Layer层中的图像是否有变化。

void SurfaceFlinger::preComposition()
{
    bool needExtraInvalidate = false;
    const LayerVector& layers(mDrawingState.layersSortedByZ);
    const size_t count = layers.size();
    for (size_t i=0 ; i<count ; i++) {
        if (layers[i]->onPreComposition()) {
            needExtraInvalidate = true;
        }
    }
    if (needExtraInvalidate) {
        signalLayerUpdate();
    }
}


1.1 每个Layer的onFrameAvailable函数

onPreComposition函数来根据mQueuedFrames来判断图像是否发生了变化,或者是mSidebandStreamChanged。

bool Layer::onPreComposition() {
    mRefreshPending = false;
    return mQueuedFrames > 0 || mSidebandStreamChanged;
}

当Layer所对应的Surface更新图像后,它所对应的Layer对象的onFrameAvailable函数会被调用来通知这种变化。
我们看Layer的onFirstRef函数,先调用BufferQueue::createBufferQueue来获取一个Buffer的消费者和生产者。然后新建了一个MonitoredProducer和一个SurfaceFlingerConsumer

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

我们再来看SurfaceFlingerConsumer的setContentsChangedListener函数

void SurfaceFlingerConsumer::setContentsChangedListener(
        const wp<ContentsChangedListener>& listener) {
    setFrameAvailableListener(listener);
    Mutex::Autolock lock(mMutex);
    mContentsChangedListener = listener;
}

上面函数是调用了基类ConsumerBase的setFrameAvailableListener函数,将listener赋给了mFrameAvailableListener。

void ConsumerBase::setFrameAvailableListener(
        const wp<FrameAvailableListener>& listener) {
    CB_LOGV("setFrameAvailableListener");
    Mutex::Autolock lock(mMutex);
    mFrameAvailableListener = listener;
}

而最终在其onFrameAvailable函数中调用了listener->onFrameAvailable函数。

void ConsumerBase::onFrameAvailable(const BufferItem& item) {
    CB_LOGV("onFrameAvailable");

    sp<FrameAvailableListener> listener;
    { // scope for the lock
        Mutex::Autolock lock(mMutex);
        listener = mFrameAvailableListener.promote();
    }

    if (listener != NULL) {
        CB_LOGV("actually calling onFrameAvailable");
        listener->onFrameAvailable(item);
    }
}
因此我们再来看看Layer的onFrameAvailable函数,主要是将mQueuedFrames加1,然后调用了SurfaceFlinger的signalLayerUpdate函数。

void Layer::onFrameAvailable(const BufferItem& item) {
    // Add this buffer from our internal queue tracker
    { // Autolock scope
        Mutex::Autolock lock(mQueueItemLock);

        // Reset the frame number tracker when we receive the first buffer after
        // a frame number reset
        if (item.mFrameNumber == 1) {
            mLastFrameNumberReceived = 0;
        }

        // Ensure that callbacks are handled in order
        while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
                    ms2ns(500));
            if (result != NO_ERROR) {
                ALOGE("[%s] Timed out waiting on callback", mName.string());
            }
        }

        mQueueItems.push_back(item);
        android_atomic_inc(&mQueuedFrames);

        // Wake up any pending callbacks
        mLastFrameNumberReceived = item.mFrameNumber;
        mQueueItemCondition.broadcast();
    }

    mFlinger->signalLayerUpdate();
}

同样在SurfaceFlinger的preComposition函数中当有Layer的图像改变了,最后也会调用SurfaceFlinger的signalLayerUpdate函数。

void SurfaceFlinger::preComposition()
{
    bool needExtraInvalidate = false;
    const LayerVector& layers(mDrawingState.layersSortedByZ);
    const size_t count = layers.size();
    for (size_t i=0 ; i<count ; i++) {
        if (layers[i]->onPreComposition()) {
            needExtraInvalidate = true;
        }
    }
    if (needExtraInvalidate) {
        signalLayerUpdate();
    }
}

SurfaceFlinger::signalLayerUpdate是调用了MessageQueue的invalidate函数

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

调用了handler的dispatchInvalidate函数,

void MessageQueue::invalidate() {
#if INVALIDATE_ON_VSYNC
    mEvents->requestNextVsync();
#else
    mHandler->dispatchInvalidate();
#endif
}

Handler::dispatchInvalidate只是发送了一个消息

void MessageQueue::Handler::dispatchInvalidate() {
    if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) {
        mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
    }
}

最后处理还是调用了SurfaceFlinger的onMessageReceived函数。

        case INVALIDATE:
            android_atomic_and(~eventMaskInvalidate, &mEventMask);
            mQueue.mFlinger->onMessageReceived(message.what);
            break;

我们再来看看SurfaceFlinger的onMessageReceived函数对NVALIDATE的处理

void SurfaceFlinger::onMessageReceived(int32_t what) {
    ATRACE_CALL();
    switch (what) {
        ......
        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;

我们先来看下handleMessageTransaction和handleMessageInvalidate函数。

bool SurfaceFlinger::handleMessageTransaction() {
    uint32_t transactionFlags = peekTransactionFlags(eTransactionMask);
    if (transactionFlags) {
        handleTransaction(transactionFlags);
        return true;
    }
    return false;
}

bool SurfaceFlinger::handleMessageInvalidate() {
    ATRACE_CALL();
    return handlePageFlip();
}

handleMessageInvalidate函数中调用了handlePageFlip函数,这个函数将会处理Layer中的缓冲区,把更新过的图像缓冲区切换到前台,等待VSync信号更新到FrameBuffer。


1.2 绘制流程

具体完整的绘制流程如图。


用户进程更新Surface图像,将导致SurfaceFlinger中的Layer发送invalidate消息,处理该消息会调用handleTransaction函数和handlePageFilp函数来更新Layer对象。一旦VSync信号到来,再调用rebuildlayerStacks setUpHWComposer doComposition postComposition函数将所有Layer的图像混合后更新到显示设备上去。


二、handleTransaction handPageFlip更新Layer对象

在上一节中的绘图的流程中,我们看到了handleTransaction和handPageFlip这两个函数通常是在用户进程更新Surface图像时会调用,来更新Layer对象。这节就主要讲解这两个函数。

2.1 handleTransaction函数

handleTransaction函数的参数是transactionFlags,不过函数中没有使用这个参数,而是通过getTransactionFlags(eTransactionMask)来重新对transactionFlags赋值,然后使用它作为参数来调用函数handleTransactionLocked。

void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
    ATRACE_CALL();

    State drawingState(mDrawingState);

    Mutex::Autolock _l(mStateLock);
    const nsecs_t now = systemTime();
    mDebugInTransaction = now;

    transactionFlags = getTransactionFlags(eTransactionMask);//产生一个新的transactionFlags变量
    handleTransactionLocked(transactionFlags);

    mLastTransactionTime = systemTime() - now;
    mDebugInTransaction = 0;
    invalidateHwcGeometry();
}

getTransactionFlags函数的参数是eTransactionMask只是屏蔽其他位。

uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) {
    return android_atomic_and(~flags, &mTransactionFlags) & flags;
}

handleTransactionLocked函数会调用每个Layer类的doTransaction函数,在分析handleTransactionLocked函数之前,我们先看看Layer类 的doTransaction函数。


2.2 Layer的doTransaction函数

下面是Layer的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) ||//如果两个对象的大小不相等,说明Layer的尺寸发生变化
                             (c.requested.h != s.requested.h);

    if (sizeChanged) {//如果Layer的尺寸发生变化,就要改变Surface的缓冲区的尺寸
        mSurfaceFlingerConsumer->setDefaultBufferSize(
                c.requested.w, c.requested.h);
    }

    if (!isFixedSize()) {
        //如果Layer不是固定尺寸的类型,比较它的实际大小和要求的改变大小
        const bool resizePending = (c.requested.w != c.active.w) ||
                                   (c.requested.h != c.active.h);

        if (resizePending && mSidebandStream == NULL) {//如果两者不一样,flags加上不更新Geometry标志
            flags |= eDontUpdateGeometryState;
        }
    }

    if (flags & eDontUpdateGeometryState)  {
    } else {
        //如果没有eDontUpdateGeometryState标志,更新active的值为request
        Layer::State& editCurrentState(getCurrentState());
        editCurrentState.active = c.requested;
    }

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

    if (c.sequence != s.sequence) {
        //如果当前state的sequence和以前state的sequence不等,设置更新标志
        flags |= eVisibleRegion;
        this->contentDirty = true;

        const uint8_t type = c.transform.getType();
        mNeedsFiltering = (!c.transform.preserveRects() ||
                (type >= Transform::SCALE));
    }

    // Commit the transaction
    commitTransaction();//将mCurrentState的值赋给mDrawingState
    return flags;
}

Layer类中的两个类型为Layer::State的成员变量mDrawingState、mCurrentState,我们来看下Layer::State类型

    struct State {
        Geometry active;//实际大小
        Geometry requested;//用户大小
        uint32_t z;//Layer的Z轴值
        uint32_t layerStack;//和显示设备的关联值
        uint8_t alpha;//Layer的透明度
        uint8_t flags;//Layer的标志
        uint8_t reserved[2];
        int32_t sequence; //序列值,Layer的属性变化一次,这个值就加1
        Transform transform;
        // 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对象的绘制了。

Layer的doTransaction函数据你是比较这两个变量,如果有不同的地方,说明在上次绘制以后,用户改变的Layer的设置,要把这种变化通过flags返回。

State的结构中有两个Geometry字段,active和requested。他们表示layer的尺寸,其中requested保存是用户设置的尺寸,而active保存的值通过计算后的实际尺寸。

State中的z字段的值就是Layer在显示轴的位置,值越小位置越靠下。

layerStack字段是用户指定的一个值,用户可以给DisplayDevice也指定一个layerStack值,只有Layer对象和DisplayDevice对象的layerStack相等,这个Layer才能在这个显示设备上输出,这样的好处是可以让显示设备只显示某个Surface的内容。例如,可以让HDMI显示设备只显示手机上播放视频的Surface窗口,但不显示Activity窗口。

sequence字段是个序列值,每当用户调用了Layer的接口,例如setAlpha、setSize或者setLayer等改变Layer对象属性的哈数,这个值都会加1。因此在doTransaction函数中能通过比较sequence值来判断Layer的属性值有没有变化。

doTransaction函数最后会调用commitTransaction函数,就是把mCurrentState赋值给mDrawingState

void Layer::commitTransaction() {
    mDrawingState = mCurrentState;
}


2.3 handleTransactionLocked函数

下面我们来分析handleTransactionLocked函数,这个函数比较长,我们分段分析


2.3.1 处理Layer的事务

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;
        }
    }
在SurfaceFlinger中也有两个类型为State的变量mCurrentState和mDrawingState,但是和Layer中的不要混起来。它的名字相同而已

    struct State {
        LayerVector layersSortedByZ;
        DefaultKeyedVector< wp<IBinder>, DisplayDeviceState> displays;
    };

结构layersSortedByZ字段保存所有参与绘制的Layer对象,而字段displays保存的是所有输出设备的DisplayDeviceState对象

这里用两个变量的目的是和Layer中使用两个变量是一样的。

上面代码根据eTraversalNeeded标志来决定是否要检查所有的Layer对象。如果某个Layer对象中有eTransactionNeeded标志,将调用它的doTransaction函数。Layer的doTransaction函数返回的flags如果有eVisibleRegion,说明这个Layer需要更新,就把mVisibleRegionsDirty设置为true


2.3.2 处理显示设备的变化

    if (transactionFlags & eDisplayTransactionNeeded) {
        //得到当前显示设备列表和之前使用的显示设备列表
        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();//以前显示设备的数量

            for (size_t i=0 ; i<dc ; i++) {
                const ssize_t j = curr.indexOfKey(draw.keyAt(i));
                if (j < 0) {//j< 0代表当前设备列表中找不到以前设备列表中的某个设备,设备被删除了
                    if (!draw[i].isMainDisplay()) {
                        ......
                        //如果不是主设备移除它
                        mDisplays.removeItem(draw.keyAt(i));
                    } else {
                        ALOGW("trying to remove the main display");
                    }
                } else {//j>0代表这个设备两个列表中都存在,再检查有没有其他变化
                    // this display is in both lists. see if something changed.
                    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) {
                        //设备的Surface已经发生了变化(Surface对象不是一个了),旧的设备必须先删除掉
                        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) {
                        //两个对象的layerStack不相等,使用当前对象的
                        if (state.layerStack != draw[i].layerStack) {
                            disp->setLayerStack(state.layerStack);
                        }
                        //如果两个对象的方向、viewport、frame不相等,使用当前对象的
                        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);
                        }
                    }
                }
            }

            // 处理显示设备增加的情况
            for (size_t i=0 ; i<cc ; i++) {
                if (draw.indexOfKey(curr.keyAt(i)) < 0) {
                //当前列表中某个设备在以前列表中没有找到,说明是增加的设备
                //创建DisplayDevice对象,把它加入到mDisplays列表中
                    ......
                    const wp<IBinder>& display(curr.keyAt(i));
                    if (dispSurface != NULL) {
                        sp<DisplayDevice> hw = new DisplayDevice(this,
                                state.type, hwcDisplayId,
                                mHwc->getFormat(hwcDisplayId), state.isSecure,
                                display, dispSurface, producer,
                                mRenderEngine->getEGLConfig());
                        ......
                        mDisplays.add(display, hw);
                        ......
                    }
                }
            }
        }
    }

这段代码的作用是处理显示设备的变化,分成3种情况:

1.显示设备减少了,需要把显示设备对应的DisplayDevice移除

2.显示设备发生了变化,例如用户设置了Surface、重新设置了layerStack、旋转了屏幕等,这就需要重新设置显示对象的属性

3.显示设备增加了,创建新的DisplayDevice加入系统中。


2.3.3 设置TransfromHit

    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;
                // 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();//清除disp
                for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
                    sp<const DisplayDevice> hw(mDisplays[dpy]);
                    if (hw->getLayerStack() == currentlayerStack) {
                        if (disp == NULL) {
                            disp = hw;//找到了一个layerStacker相同的显示设备
                        } else {
                            disp = NULL;//如果有两个显示设备的layerStacker相同,都不用
                            break;
                        }
                    }
                }
            }
            if (disp == NULL) {
                // 没有找到具有相同layerStack的显示设备,使用缺省设备
                disp = getDefaultDisplayDevice();
            }
            layer->updateTransformHint(disp);//设置Layer对象的TransformHint
        }
    }

这段代码的作用是根据每种显示设备的不同,设置和显示设备关联在一起的Layer(主要看Layer的layerStack是否和DisplayDevice的layerStack)的TransformHint(主要指设备的显示方向orientation)。



2.3.4 处理Layer增加情况

    const LayerVector& layers(mDrawingState.layersSortedByZ);
    if (currentLayers.size() > layers.size()) {
        // 如果有Layer加入,设置需要更新
        mVisibleRegionsDirty = true;
    }

    // 处理有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) {
                //如果这个Layer已经不存在了,把它的所在区域设置为需要更新的区域
                const Layer::State& s(layer->getDrawingState());
                Region visibleReg = s.transform.transform(
                        Region(Rect(s.active.w, s.active.h)));
                invalidateLayerStack(s.layerStack, visibleReg);
            }
        }
    }

这段代码处理Layer的增加情况,如果Layer增加了,需要重新计算设备的更新区域,因此把mVisibleRegionsDirty设为true,如果Layer删除了,需要把Layer的可见区域加入到系统需要更新的区域中。


2.3.5 设置mDrawingState

    commitTransaction();

    updateCursorAsync();

调用commitTransaction和updateCursorAsync函数 commitTransaction函数作用是把mDrawingState的值设置成mCurrentState的值。而updateCursorAsync函数会更新所有显示设备中光标的位置。


2.3.6 小结

handleTransaction函数的作用的就是处理系统在两次刷新期间的各种变化。SurfaceFlinger模块中不管是SurfaceFlinger类还是Layer类,都采用了双缓冲的方式来保存他们的属性,这样的好处是刚改变SurfaceFlinger对象或者Layer类对象的属性是,不需要上锁,大大的提高了系统效率。只有在最后的图像输出是,才进行一次上锁,并进行内存的属性变化处理。正因此,应用进程必须收到VSync信号才开始改变Surface的内容。


2.4 handlePageFlip函数

handlePageFlip函数代码如下:

bool SurfaceFlinger::handlePageFlip()
{
    Region dirtyRegion;

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

    Vector<Layer*> layersWithQueuedFrames;
    //查找需要更新的Layer
    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();
        }
    }
    for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) {
        Layer* layer = layersWithQueuedFrames[i];
        const Region dirty(layer->latchBuffer(visibleRegions));
        layer->useSurfaceDamage();
        const Layer::State& s(layer->getDrawingState());
        invalidateLayerStack(s.layerStack, dirty);
    }

    mVisibleRegionsDirty |= visibleRegions;

    if (frameQueued && layersWithQueuedFrames.empty()) {
        signalLayerUpdate();
    }

    return !layersWithQueuedFrames.empty();
}

handlePageFlip函数先调用每个Layer对象的hasQueuedFrame函数,确定这个Layer对象是否有需要更新的图层,然后把需要更新的Layer对象放到layersWithQueuedFrames中。

我们先来看Layer的hasQueuedFrame方法就是看其mQueuedFrames是否大于0 和mSidebandStreamChanged。前面小节分析只要Surface有数据写入,就会调用Layer的onFrameAvailable函数,然后mQueuedFrames值加1.

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

继续看handlePageFlip函数,接着调用需要更新的Layer对象的latchBuffer函数,然后根据返回的更新区域调用invalidateLayerStack函数来设置更新设备对象的更新区域。
下面我们看看latchBuffer函数

Region Layer::latchBuffer(bool& recomputeVisibleRegions)
{
    ATRACE_CALL();

    if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
        // mSidebandStreamChanged was true
        mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
        if (mSidebandStream != NULL) {
            setTransactionFlags(eTransactionNeeded);
            mFlinger->setTransactionFlags(eTraversalNeeded);
        }
        recomputeVisibleRegions = true;

        const State& s(getDrawingState());
        return s.transform.transform(Region(Rect(s.active.w, s.active.h)));
    }

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

        uint64_t maxFrameNumber = 0;
        {
            Mutex::Autolock lock(mQueueItemLock);
            maxFrameNumber = mLastFrameNumberReceived;
        }

        status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,//更新纹理
                mFlinger->mPrimaryDispSync, maxFrameNumber);
        if (updateResult == BufferQueue::PRESENT_LATER) {
            mFlinger->signalLayerUpdate();//如果结果是推迟处理,发送Invalidate消息
            return outDirtyRegion;
        } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
            // If the buffer has been rejected, remove it from the shadow queue
            // and return early
            Mutex::Autolock lock(mQueueItemLock);
            mQueueItems.removeAt(0);
            android_atomic_dec(&mQueuedFrames);
            return outDirtyRegion;
        } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
            // This can occur if something goes wrong when trying to create the
            // EGLImage for this buffer. If this happens, the buffer has already
            // been released, so we need to clean up the queue and bug out
            // early.
            {
                Mutex::Autolock lock(mQueueItemLock);
                mQueueItems.clear();
                android_atomic_and(0, &mQueuedFrames);
            }

            // Once we have hit this state, the shadow queue may no longer
            // correctly reflect the incoming BufferQueue's contents, so even if
            // updateTexImage starts working, the only safe course of action is
            // to continue to ignore updates.
            mUpdateTexImageFailed = true;

            return outDirtyRegion;
        }

        { // Autolock scope
            auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();

            Mutex::Autolock lock(mQueueItemLock);

            // Remove any stale buffers that have been dropped during
            // updateTexImage
            while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
                mQueueItems.removeAt(0);
                android_atomic_dec(&mQueuedFrames);
            }

            mQueueItems.removeAt(0);
        }


        // Decrement the queued-frames count.  Signal another event if we
        // have more frames pending.
        if (android_atomic_dec(&mQueuedFrames) > 1) {//减少mQueuedFrames的值
            mFlinger->signalLayerUpdate();//如果还有更多frame需要处理,要发消息
        }

        if (updateResult != NO_ERROR) {
            // something happened!
            recomputeVisibleRegions = true;
            return outDirtyRegion;
        }

        //更新mActiveBuffer,得到现在需要输出的图像数据
        mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer();
        if (mActiveBuffer == NULL) {
            return outDirtyRegion;//出错
        }

        mRefreshPending = true;
        mFrameLatencyNeeded = true;
        //下面根据各种情况是否重新计算更新区域
        if (oldActiveBuffer == NULL) {
             // the first time we receive a buffer, we need to trigger a
             // geometry invalidation.
            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;
        }

        // FIXME: postedRegion should be dirty & bounds
        Region dirtyRegion(Rect(s.active.w, s.active.h));

        // transform the dirty region to window-manager space
        outDirtyRegion = (s.transform.transform(dirtyRegion));
    }
    return outDirtyRegion;
}

LatchBuffer函数调用updateTextImage来得到需要的图像。这里参数r是Reject对象,其作用是判断在缓冲区的尺寸是否符合要求。调用updateTextImage函数如果得到的结果是PRESENT_LATER,表示推迟处理,然后调用signalLayerUpdate函数来发送invalidate消息,这次绘制过程就不处理这个Surface的图像了。

如果不需要推迟处理,把mQueuedFrames的值减1.

最后LatchBuffer函数调用mSurfaceFlingerConsumer的getCurrentBuffer来取回当前的图像缓冲区指针,保存在mActiveBuffer中。


2.5 小结

这样经过handleTransaction handlePageFlip两个函数处理,SurfaceFlinger中无论是Layer属性的变化还是图像的变化都处理好了,只等VSync信号到来就可以输出了。



三、rebuildLayerStacks函数

前面介绍,VSync信号到来后,先是调用了rebuildLayerStacks函数

void SurfaceFlinger::rebuildLayerStacks() {
    // rebuild the visible layer list per screen
    if (CC_UNLIKELY(mVisibleRegionsDirty)) {
        ATRACE_CALL();
        mVisibleRegionsDirty = false;
        invalidateHwcGeometry();
        
        //计算每个显示设备上可见的Layer
        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->isDisplayOn()) {
                //计算每个layer的可见区域,确定设备需要重新绘制的区域
                SurfaceFlinger::computeVisibleRegions(layers,
                        hw->getLayerStack(), dirtyRegion, opaqueRegion);

                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()) {
                        //只需要和显示设备的LayerStack相同的layer
                        Region drawRegion(tr.transform(
                                layer->visibleNonTransparentRegion));
                        drawRegion.andSelf(bounds);
                        if (!drawRegion.isEmpty()) {
                            //如果Layer的显示区域和显示设备的窗口有交集
                            //把Layer加入列表中
                            layersSortedByZ.add(layer);
                        }
                    }
                }
            }
            //设置显示设备的可见Layer列表
            hw->setVisibleLayersSortedByZ(layersSortedByZ);
            hw->undefinedRegion.set(bounds);
            hw->undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
            hw->dirtyRegion.orSelf(dirtyRegion);
        }
    }
}

rebuildLayerStacks函数的作用是重建每个显示设备的可见layer对象列表。对于按显示轴(Z轴)排列的Layer对象,排在最前面的当然会优先显示,但是Layer图像可能有透明域,也可能有尺寸没有覆盖整个屏幕,因此下面的layer也有显示的机会。rebuildLayerStacks函数对每个显示设备,先计算和显示设备具有相同layerStack值的Layer对象在该显示设备上的可见区域。然后将可见区域和显示设备的窗口区域有交集的layer组成一个新的列表,最后把这个列表设置到显示设备对象中。

computeVisibleRegions函数首先计算每个Layer在设备上的可见区域visibleRegion。计算方法就是用整个Layer的区域减去上层所有不透明区域aboveOpaqueLayers。而上层所有不透明区域值是一个逐层累计的过程,每层都需要把自己的不透明区域累加到aboveOpaqueLayers中。

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

其次,计算整个显示设备需要更新的区域outDirtyRegion。outDirtyRegion的值也是累计所有层的需要重回的区域得到的。如果Layer中的显示内容发生了变化,则整个可见区域visibleRegion都需要更新,同时还要包括上一次的可见区域,然后在去掉被上层覆盖后的区域得到的就是Layer需要更新的区域。如果Layer显示的内容没有变化,但是考虑到窗口大小的变化或者上层窗口的变化,因此Layer中还是有区域可以需要重绘的地方。这种情况下最简单的算法是用Layer计算出可见区域减去以前的可见区域就可以了。但是在computeVisibleRegions函数还引入了被覆盖区域,通常被覆盖区域和可见区域并不重复,因此函数中计算暴露区域是用可见区域减去被覆盖区域的。


四、setUpHWComposer函数

setUpHWComposer函数的作用是更新HWComposer对象中图层对象列表以及图层属性。

void SurfaceFlinger::setUpHWComposer() {
    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
        bool dirty = !mDisplays[dpy]->getDirtyRegion(false).isEmpty();
        bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
        bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers;
        bool mustRecompose = dirty && !(empty && wasEmpty);
        mDisplays[dpy]->beginFrame(mustRecompose);

        if (mustRecompose) {
            mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty;
        }
    }

    HWComposer& hwc(getHwComposer());//得到系统HWComposer对象
    if (hwc.initCheck() == NO_ERROR) {
        // build the h/w work list
        if (CC_UNLIKELY(mHwWorkListDirty)) {
            mHwWorkListDirty = false;
            for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
                sp<const DisplayDevice> hw(mDisplays[dpy]);
                const int32_t id = hw->getHwcDisplayId();
                if (id >= 0) {
                    const Vector< sp<Layer> >& currentLayers(
                        hw->getVisibleLayersSortedByZ());
                    const size_t count = currentLayers.size();
                    //根据Layer数量在HWComposer中创建hwc_layer_list_t列表
                    if (hwc.createWorkList(id, count) == NO_ERROR) {
                        ......
                    }
                }
            }
        }

        // set the per-frame data
        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
            sp<const DisplayDevice> hw(mDisplays[dpy]);
            const int32_t id = hw->getHwcDisplayId();
            if (id >= 0) {
                ......
                for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
                    const sp<Layer>& layer(currentLayers[i]);
                    //将Layer的mActiveBuffer设置到HWComposer中
                    layer->setPerFrameData(hw, *cur);
                }
            }
        }

        // If possible, attempt to use the cursor overlay on each display.
        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
            sp<const DisplayDevice> hw(mDisplays[dpy]);
            const int32_t id = hw->getHwcDisplayId();
            if (id >= 0) {
                const Vector< sp<Layer> >& currentLayers(
                    hw->getVisibleLayersSortedByZ());
                const size_t count = currentLayers.size();
                HWComposer::LayerListIterator cur = hwc.begin(id);
                const HWComposer::LayerListIterator end = hwc.end(id);
                for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
                    const sp<Layer>& layer(currentLayers[i]);
                    if (layer->isPotentialCursor()) {
                        cur->setIsCursorLayerHint();
                        break;
                    }
                }
            }
        }

        status_t err = hwc.prepare();
        ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));

        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
            sp<const DisplayDevice> hw(mDisplays[dpy]);
            hw->prepareFrame(hwc);
        }
    }
}

HWComposer中有一个类型为DisplayData结构的数组mDisplayData,它维护着每个显示设备的信息。DisplayData结构中有一个类型为hwc_display_contents_l字段list,这个字段又有一个hwc_layer_l类型的数组hwLayers,记录该显示设备所有需要输出的Layer信息。

setUpHWComposer函数调用HWComposer的createWorkList函数就是根据每种显示设备的Layer数量,创建和初始化hwc_display_contents_l对象和hwc_layer_l数组

创建完HWComposer中的列表后,接下来是对每个Layer对象调用它的setPerFrameData函数,参数是HWComposer和HWCLayerInterface。setPerFrameData函数将Layer对象的当前图像缓冲区mActiveBuffer设置到HWCLayerInterface对象对应的hwc_layer_l对象中。

HWComposer类中除了前面介绍的Gralloc还管理着Composer模块,这个模块实现了硬件的图像合成功能。setUpHWComposer函数接下来调用HWComposer类的prepare函数,而prepare函数会调用Composer模块的prepare接口。最后到各个厂家的实现hwc_prepare函数将每种HWComposer中的所有图层的类型都设置为HWC_FRAMEBUFFER就结束了。


五、合成所有层的图像 (doComposition函数)

doComposition函数是合成所有层的图像,代码如下:

void SurfaceFlinger::doComposition() {
    ATRACE_CALL();
    const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
        const sp<DisplayDevice>& hw(mDisplays[dpy]);
        if (hw->isDisplayOn()) {
            // transform the dirty region into this screen's coordinate space
            const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));

            // 图像合成
            doDisplayComposition(hw, dirtyRegion);

            hw->dirtyRegion.clear();
            hw->flip(hw->swapRegion);
            hw->swapRegion.clear();
        }
        // inform the h/w that we're done compositing
        hw->compositionComplete();
    }
    postFramebuffer();
}

doComposition函数针对每种显示设备调用doDisplayComposition函数来合成,合成后调用postFramebuffer函数,我们先来看看doDisplayComposition函数

void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw,
        const Region& inDirtyRegion)
{
    bool isHwcDisplay = hw->getHwcDisplayId() >= 0;
    if (!isHwcDisplay && inDirtyRegion.isEmpty()) {
        return;
    }

    Region dirtyRegion(inDirtyRegion);

    //swapRegion设置为需要更新的区域
    hw->swapRegion.orSelf(dirtyRegion);

    uint32_t flags = hw->getFlags();//获得显示设备支持的更新方式标志
    if (flags & DisplayDevice::SWAP_RECTANGLE) {//支持矩阵更新        
        dirtyRegion.set(hw->swapRegion.bounds());
    } else {
        if (flags & DisplayDevice::PARTIAL_UPDATES) {//支持部分更新
            dirtyRegion.set(hw->swapRegion.bounds());
        } else {
            //将更新区域调整为整个窗口大小
            dirtyRegion.set(hw->bounds());
            hw->swapRegion = dirtyRegion;
        }
    }

    if (CC_LIKELY(!mDaltonize && !mHasColorMatrix)) {
        if (!doComposeSurfaces(hw, dirtyRegion)) return;//合成
    } else {
        RenderEngine& engine(getRenderEngine());
        mat4 colorMatrix = mColorMatrix;
        if (mDaltonize) {
            colorMatrix = colorMatrix * mDaltonizer();
        }
        mat4 oldMatrix = engine.setupColorTransform(colorMatrix);
        doComposeSurfaces(hw, dirtyRegion);//合成
        engine.setupColorTransform(oldMatrix);
    }

    // update the swap region and clear the dirty region
    hw->swapRegion.orSelf(dirtyRegion);

    // swap buffers (presentation)
    hw->swapBuffers(getHwComposer());//没有硬件composer的情况,输出图像
}

doDisplayComposition函数根据显示设备支持的更新方式,重新设置需要更新区域的大小。
真正的合成工作是在doComposerSurfaces函数中完成,这个函数在layer的类型为HWC_FRAMEBUFFER,或者不支持硬件的composer的情况下,调用layer的draw函数来一层一层低合成最后的图像。

合成完后,doDisplayComposition函数调用了hw的swapBuffers函数,这个函数前面介绍过了,它将在系统不支持硬件的composer情况下调用eglSwapBuffers来输出图像到显示设备。


六、postFramebuffer函数

上一节的doComposition函数最后调用了postFramebuffer函数,代码如下:

void SurfaceFlinger::postFramebuffer()
{
    ATRACE_CALL();

    const nsecs_t now = systemTime();
    mDebugInSwapBuffers = now;

    HWComposer& hwc(getHwComposer());
    if (hwc.initCheck() == NO_ERROR) {
        if (!hwc.supportsFramebufferTarget()) {
            // EGL spec says:
            //   "surface must be bound to the calling thread's current context,
            //    for the current rendering API."
            getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
        }
        hwc.commit();
    }

    ......
}

postFramebuffer先判断系统是否支持composer,如果不支持,我们知道图像已经在doComposition函数时调用hw->swapBuffers输出了,就返回了。如果支持硬件composer,postFramebuffer函数将调用HWComposer的commit函数继续执行。

status_t HWComposer::commit() {
    int err = NO_ERROR;
    if (mHwc) {
        if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
            // On version 1.0, the OpenGL ES target surface is communicated
            // by the (dpy, sur) fields and we are guaranteed to have only
            // a single display.
            mLists[0]->dpy = eglGetCurrentDisplay();
            mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW);
        }

        for (size_t i=VIRTUAL_DISPLAY_ID_BASE; i<mNumDisplays; i++) {
            DisplayData& disp(mDisplayData[i]);
            if (disp.outbufHandle) {
                mLists[i]->outbuf = disp.outbufHandle;
                mLists[i]->outbufAcquireFenceFd =
                        disp.outbufAcquireFence->dup();
            }
        }

        err = mHwc->set(mHwc, mNumDisplays, mLists);
        ......
    }
    return (status_t)err;
}

commit函数又调用了composer模块的set接口来完成工作,这就到HAL层的代码了,最后输出到显示屏上。





版权声明:本文为博主原创文章,未经博主允许不得转载。

Android图形显示系统——概述

序Android的图形显示系统,虽然感觉自己基本了解了,有问题基本都能解决,但要写时,一是觉得千头万绪无从下笔,一是发现还有很多并没有真正搞懂。开工写这套体系,也顺便查漏补缺下。Android图形显示...

Android显示系统设计框架介绍

1. Linux内核提供了统一的framebuffer显示驱动,设备节点/dev/graphics/fb*或者/dev/fb*,以fb0表示第一个显示屏,当前实现中只用到了一个显示屏。 2. Andr...

Android图形显示系统(一)

本文讲解的内容是Android4.1以后的系统机制,将从整体上分析Android图形显示系统的结构,不深入分析每一层内部的代码实现,更多的是使用流程图和结构图来让大家理解Android是如何绘制、合成...

Android显示系统框架原理介绍

1. android显示系统整体框架         最上面一层为应用程序,根据数据类型以及应用的不同可以分为几种。        第一种是最普通的应用,如 UI 界面的显示,...

玩转Android Camera开发(三):国内首发---使用GLSurfaceView预览Camera 基础拍照demo

GLSurfaceView是OpenGL中的一个类,也是可以预览Camera的,而且za

Android SurfaceTexture和GLSurfaceView做Camera预览

GLSurfaceView是OpenGL中的一个类,也是可以预览Camera的,而且在预览Camera上有其独到之处。独到之处在哪?当使用Surfaceview无能为力、痛不欲生时就只有使用GLSur...

Android4.0 SurfaceTexture

source link: http://developer.android.com/reference/android/graphics/SurfaceTexture.html public...

TextureView+SurfaceTexture+OpenGL ES来播放视频(三)

做好的Demo截图 opengl-video 前言 讲了这么多,可能有人要问了,播放视频用个android封装的VideoView或者用MediaPlayer+SurfaceView来进行播放视...
  • prike
  • prike
  • 2017年10月25日 16:13
  • 69

SurfaceView, TextureView, SurfaceTexture等的区别

SurfaceView, TextureView, SurfaceTexture等的区别 SurfaceView, GLSurfaceView, SurfaceTexture以及Text...

Android应用程序UI硬件加速渲染的Display List构建过程分析

在硬件加速渲染环境中,Android应用程序窗口的UI渲染是分两步进行的。第一步是构建Display List,发生在应用程序进程的Main Thread中;第二步是渲染Display List,发生...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android6.0 显示系统(六) 图像的输出过程
举报原因:
原因补充:

(最多只允许输入30个字)