BufferQueue分析:消费者从Buffer队列取出的过程

Layer收到onFrameAvaliable通知后,会通知SurfaceFlinger更新,重新进行图像合成
在SurfaceFlinger重新合成图像的过程中,会遍历所有发生变化的Layer,此时调用Layer的latchBuffer函数去BufferQueue中拿方才生产者入队的Buffer进行处理

Layer.latchBuffer


Region Layer::latchBuffer(bool& recomputeVisibleRegions)
{
    ATRACE_CALL();
    //如果mSidebandStreamChanged为true, 设置flag为eTransactionNeeded, recomputeVisibleRegions为true
    //然后直接返回
    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.active.transform.transform(Region(Rect(s.active.w, s.active.h)));
    }
    //如果Layer中有待处理的BufferItem
    Region outDirtyRegion;
    if (mQueuedFrames > 0 || mAutoRefresh) {

        // 如果已经调用了 updateTexImage() 方法,但是还没有执行图形合成,则跳过这个Layer,直接返回
        if (mRefreshPending) {
            return outDirtyRegion;
        }

        //获取旧的Buffer的状态
        const State& s(getDrawingState());
        const bool oldOpacity = isOpaque(s);
        sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;

        
        //初始化Reject对象,用于判断当前Buffer是否会被拒绝
        Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
                getProducerStickyTransform() != 0, mName.string(),
                mOverrideScalingMode);

        ......

        //调用updateTextureImage,将Buffer内容更新到Layer对应的纹理中。
        bool queuedBuffer = false;
        status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
                mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,
                mLastFrameNumberReceived);
        if (updateResult == BufferQueue::PRESENT_LATER) {
            // 生产者如果不希望Buffer立刻显示,则通知SurfaceFLinger 下次Vsync到来时再进行更新,然后直接返回。
            mFlinger->signalLayerUpdate();
            return outDirtyRegion;
        } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
            // 如果Buffer被拒绝,则从Layer队列移除,mQueueFrame计数 -1,然后直接返回
            if (queuedBuffer) {
                Mutex::Autolock lock(mQueueItemLock);
                mQueueItems.removeAt(0);
                android_atomic_dec(&mQueuedFrames);
            }
            return outDirtyRegion;
        } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
            // 当尝试创建EGLImage的时候失败, 表明对应的GraphicBuffer已经被释放掉了,需要情况Layer中的mQueueItem列表,将
            // 计数重置为0, 然后直接返回
            if (queuedBuffer) {
                Mutex::Autolock lock(mQueueItemLock);
                mQueueItems.clear();
                android_atomic_and(0, &mQueuedFrames);
            }

            mUpdateTexImageFailed = true;

            return outDirtyRegion;
        }

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

            Mutex::Autolock lock(mQueueItemLock);

            // 丢弃过时的Buffer缓冲区
            while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
                mQueueItems.removeAt(0);
                android_atomic_dec(&mQueuedFrames);
            }
            mQueueItems.removeAt(0);
        }


        // 如果处理玩完当前的Buffer后,Layer队列中仍然还要待处理的Buffer,则通知SurfaceFLinger 下次Vsync到来时再进行更新
        if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1)
                || mAutoRefresh) {
            mFlinger->signalLayerUpdate();
        }

        if (updateResult != NO_ERROR) {
            // update发生错误,直接返回
            recomputeVisibleRegions = true;
            return outDirtyRegion;
        }

        // update the active buffer
        mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer();
        if (mActiveBuffer == NULL) {
            // this can only happen if the very first buffer was rejected.
            return outDirtyRegion;
        }

        mRefreshPending = true;
        mFrameLatencyNeeded = true;
        if (oldActiveBuffer == NULL) {
             // 第一次接收的Buffer,需要计算VisibleRegion
            recomputeVisibleRegions = true;
         }
 
        //和旧的Buffer相比如果发生了变化,这将recomputeVisibleRegions设置为true, 表明需要重新计算Layer的Region
        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;
                mFreezePositionUpdates = false;
            }
        }

        mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
        if (oldOpacity != isOpaque(s)) {
            recomputeVisibleRegions = true;
        }
        //记录这个Buffer的FrameNumber计数
        mCurrentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();

         
        //记录下发生变化的区域,并返回给调用者
        Region dirtyRegion(Rect(s.active.w, s.active.h));

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

latchBuffer比较长, 主要作用分析是否需要重新计算当前Layer的visibleRegion

  • 1:判断SidebandStream是否发生变换,如果发生变化则需要更新真个Layer
  • 2:调用updateTextureImage函数来更新Buffer, 在这个函数中会调用acquireBuffer从BufferQueue队列中获取Buffer,参数为Rejector,顾名思义,这个在updateTextureImage函数中用来判断是否拒绝这个Buffer的
    这个函数返回值分为以几种:
    PRESENT_LATER:生产者如果不希望Buffer立刻显示,则通知SurfaceFLinger 下次Vsync到来时再进行更新
    BUFFER_REJECTED:如果Buffer被拒绝,则从Layer队列移除,mQueueFrame计数 -1
    UPDATE_FAILED:当尝试创建EGLImage的时候失败, 表明对应的GraphicBuffer已经被释放掉了,需要情况Layer中的mQueueItem列表,将计数重置为0, 然后直接返回
  • 3:丢弃队列中所有过时的Buffer
  • 4:如果处理玩完当前的Buffer后,Layer队列中仍然还要待处理的Buffer,则通知SurfaceFLinger 下次Vsync到来时再进行更新
  • 5:和旧的Buffer相比如果发生了变化,这将recomputeVisibleRegions设置为true, 表明需要重新计算Layer的Region
  • 6:记录下发生变化的区域,返回给调用者

接着看下updateTextureImage方法


status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
        const DispSync& dispSync, bool* autoRefresh, bool* queuedBuffer,
        uint64_t maxFrameNumber)
{
    ......

    // 检查EGL的状态,确保和上一次的EGL状态相同
    status_t err = checkAndUpdateEglStateLocked();


    BufferItem item;

    // 从Buffer队列中获取下一个Buffer.
    err = acquireBufferLocked(&item, computeExpectedPresent(dispSync),
            maxFrameNumber);
    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;
    }

    //调用参数传入的Reject对象,判断Buffer是否符合我们的条件
    int slot = item.mSlot;
    if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) {
        releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, EGL_NO_SYNC_KHR);
        return BUFFER_REJECTED;
    }


    //更新Buffer,并且释放上一个Buffer
    err = updateAndReleaseLocked(item);
    return err;
}

updateTextureImage函数主要包含个流程
1:acquireBufferLocked从BufferQueue中获取Buffer,拿到Buffer后,将Buffer保存在mSlots[item->mSlot].mGraphicBuffer中。
2:调用参数传入的Rejecter对象。来判断图像缓冲区Buffer是否符合条件。
3:调用updateAndReleaseLocked函数更新Buffer,并且释放掉上一个Buffer

SurfaceFlingerConsumer.acquireBufferLocked

status_t SurfaceFlingerConsumer::acquireBufferLocked(BufferItem* item,
        nsecs_t presentWhen, uint64_t maxFrameNumber) {
    status_t result = GLConsumer::acquireBufferLocked(item, presentWhen,
            maxFrameNumber);
    if (result == NO_ERROR) {
        mTransformToDisplayInverse = item->mTransformToDisplayInverse;
        mSurfaceDamage = item->mSurfaceDamage;
    }
    return result;
}

SurfaceFlingerConsumer的acquireBufferLocked直接调用了父类的acquireBufferLocked函数。

status_t GLConsumer::acquireBufferLocked(BufferItem *item,
        nsecs_t presentWhen, uint64_t maxFrameNumber) {
    //调用父类ConsumerBase的acquireBufferLocked函数获取新的Buffer
    status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen,
            maxFrameNumber);

    //然后根据获取的新GraphicBuffer创建一个EglImage,保存在GLConsumer的数组mEglSlots中
    if (item->mGraphicBuffer != NULL) {
        int slot = item->mSlot;
        mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
    }

    return NO_ERROR;
}

GLConsumer的acquireBufferLocked函数也比较简单,调用父类ConsumerBase的acquireBufferLocked函数获取新的Buffer,然后根据获取的新GraphicBuffer创建一个EglImage,保存在GLConsumer的数组mEglSlots中。
GLConsumer维护了一个数组mEglSlots,和前面讲的mSlots类似,将EglImage对象保存在数组对应的slot位置上
同理GLConsumer的acquireBufferLocked也是直接调用BufferQueueConsumer的方法。

status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
        nsecs_t expectedPresent, uint64_t maxFrameNumber) {
    ATRACE_CALL();

    int numDroppedBuffers = 0;
    sp<IProducerListener> listener;
    {
        Mutex::Autolock lock(mCore->mMutex);

        //统计Consumer acquire buffer的数量,以及是否超过最大acquire的限制
        int numAcquiredBuffers = 0;
        for (int s : mCore->mActiveBuffers) {
            if (mSlots[s].mBufferState.isAcquired()) {
                ++numAcquiredBuffers;
            }
        }
        if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
            BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)",
                    numAcquiredBuffers, mCore->mMaxAcquiredBufferCount);
            return INVALID_OPERATION;
        }

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

        // 如果Buffer被生产者指定了显示的时间,不到显示时间的Buffer不会被获取
        // 如果指定了显示时间,但是在这帧画面前还有Buffer等待显示,此时可能会丢掉部分Buffer
        if (expectedPresent != 0 && !mCore->mQueue.empty()) {
            const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second

            //如果队列中待显示的Buffer大于1个,且第一个要显示的是指定时间的Buffer
            while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
                //去队列中的第二个Buffer
                const BufferItem& bufferItem(mCore->mQueue[1]);

                  
                 
                //如果第二个已经超过预期显示时间1S(已经太迟,来不及显示了)或者,还没有到显示时间,则不需要获取Buffer
                nsecs_t desiredPresent = bufferItem.mTimestamp;
                if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
                        desiredPresent > expectedPresent) {

                    break;
                }
                //否则立刻获取第二个Buffer,准备显示第二个Buffer,第一个Buffer丢掉
                if (!front->mIsStale) {
                    // 将第一个Buffer值为FREE状态
                    mSlots[front->mSlot].mBufferState.freeQueued();

                    ......


                    listener = mCore->mConnectedProducerListener;
                    ++numDroppedBuffers;
                }
                //从队列中移除第一个Buffer,再次循化查找
                mCore->mQueue.erase(front);
                front = mCore->mQueue.begin();
            }

            // 如果拿到的Buffer 在下一个Vsync到来时还未到显示时间,且预期显示时间小于下一次Vsync + 1S 的时间,说明还未显示但是即将要显示,返回 PRESENT_LANTER
            nsecs_t desiredPresent = front->mTimestamp;
            bool bufferIsDue = desiredPresent <= expectedPresent ||
                    desiredPresent > expectedPresent + MAX_REASONABLE_NSEC;
            bool consumerIsReady = maxFrameNumber > 0 ?
                    front->mFrameNumber <= maxFrameNumber : true;
            if (!bufferIsDue || !consumerIsReady) {
                
                return PRESENT_LATER;
            }
        }

        //查找到指定的Buffer,保存到出参outBuffer中
        int slot = BufferQueueCore::INVALID_BUFFER_SLOT;

        if (sharedBufferAvailable && mCore->mQueue.empty()) {
          ......
          //shareBuffer的逻辑暂时不管
        } else {
            slot = front->mSlot;
            *outBuffer = *front;
        }


        if (!outBuffer->mIsStale) {
            //设置mAcquireCalled变量为true
            mSlots[slot].mAcquireCalled = true;
            if (mCore->mQueue.empty()) {
                mSlots[slot].mBufferState.acquireNotInQueue();
            } else {
                 //设置对应BufferState的状态为ACQUIRED状态
                mSlots[slot].mBufferState.acquire();
            }
            mSlots[slot].mFence = Fence::NO_FENCE;
        }

        // 如果buffer已经被acquire过了,则把graphicBuffer的指针置为NULL,防止重复内存映射
        if (outBuffer->mAcquireCalled) {
            outBuffer->mGraphicBuffer = NULL;
        }
        //将Buffer从BufferQueue的mQueue队列中移除
        mCore->mQueue.erase(front);

        ......
    }

    //如果有直接丢弃的Buffer,需要通知有Buffer释放
    if (listener != NULL) {
        for (int i = 0; i < numDroppedBuffers; ++i) {
            listener->onBufferReleased();
        }
    }

    return NO_ERROR;
}

BufferQueueConsumer的acquiredBuffer函数从BufferQueue中拿准备好的Buffer数据。
1:先统计消费者acquire的buffer的数量是否查过最大限度,超过的话则禁止获取
2:遍历mQueue队列,获取合适的Buffer。如果Queue中等待显示的Buffer数量大于1,需要查看队列后边是否有指定显示时间且显示时间已经到的Buffer,有到话则直接放弃前边一个,显示后一个。循环处理,直到找到最紧急显示到Buffer。
3:根据找到的Buffer判断该Buffer是有需要立刻显示,如果离指定显示时间大于一定时间,则发挥PRESENT_LATER,此次显示不再处理该Buffer。
4:拿到需要显示的Buffer,设置需要显示Buffer的状态为ACQUIRED,并且将它从mQueue等待对了移除。
5:如果有遗弃的Buffer,需要同时有Buffer释放。

分析到这里Buffer已经从BufferQueue队列获取到了,下一步看如何更新Buffer。

SurfaceFlinger.updateAndReleaseLocked

status_t GLConsumer::updateAndReleaseLocked(const BufferItem& item,
        PendingRelease* pendingRelease)
{
    status_t err = NO_ERROR;
    //获取要更新的GraphicBuffer slot值
    int slot = item.mSlot;
    //判断当前Consumer对应的纹理贴图是否已经Attch到当前的EGLContext上了
    //创建Layer的时候,会为每个Layer创建了一个纹理。同时创建了SurfaceFlingerConsumer,将纹理的ID传给了Consumer.此时,纹理默认是attach到EGL context上的。
    //如果EGL没有Context,则直接释放掉当前Buffer。不做更新处理
    if (!mAttached) {
        GLC_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL "
                "ES context");
        releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
                mEglDisplay, EGL_NO_SYNC_KHR);
        return INVALID_OPERATION;
    }

    // 检查EGL状态和上次相比是否发生了变化?
    err = checkAndUpdateEglStateLocked();
    if (err != NO_ERROR) {
        releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
                mEglDisplay, EGL_NO_SYNC_KHR);
        return err;
    }

    // 为每个slot中的GraphicBuffer创建一个EGLImage,保存在GLConsumer的mEglSlots数组中。
    err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
    if (err != NO_ERROR) {
        GLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
                mEglDisplay, slot);
        releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
                mEglDisplay, EGL_NO_SYNC_KHR);
        return UNKNOWN_ERROR;
    }

    // 如果新获取GraphicBuffer和旧的graphicBuffer发生了变化,需要释放掉旧的graphicBuffer
    if (slot != mCurrentTexture) {
        err = syncForReleaseLocked(mEglDisplay);
        if (err != NO_ERROR) {
            // 旧的buffer无法释放,则释放掉新获取的GraphicBuffer
            releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer,
                    mEglDisplay, EGL_NO_SYNC_KHR);
            return err;
        }
    }

    sp<EglImage> nextTextureImage = mEglSlots[slot].mEglImage;

    // 释放掉旧的buffer
    if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
        if (pendingRelease == nullptr) {
            status_t status = releaseBufferLocked(
                    mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
                    mEglDisplay, mEglSlots[mCurrentTexture].mEglFence);
            if (status < NO_ERROR) {
                GLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)",
                        strerror(-status), status);
                err = status;
                // keep going, with error raised [?]
            }
        } else {
            ......
        }
    }

    // 更新GLConsumer的状态,保存Buffer的内容.
    mCurrentTexture = slot;
    mCurrentTextureImage = nextTextureImage;
    mCurrentCrop = item.mCrop;
    mCurrentTransform = item.mTransform;
    mCurrentScalingMode = item.mScalingMode;
    mCurrentTimestamp = item.mTimestamp;
    mCurrentFence = item.mFence;
    mCurrentFrameNumber = item.mFrameNumber;

    computeCurrentTransformMatrixLocked();

    return err;
}

updateAndRelease方法从名称就可看出其操作内容。更新新Buffer,释放旧Buffer。
每一个Layer都和一个Surface对应, Surface在App端,是操作和填充当前窗口的接口,而Layer则在SurfaceFlinger端来描述这个窗口。Layer在创建的时候会创建一个纹理Texture,这个Texture id也保存在了SurfaceFlingerConsumer中。SurfaceFlinger绘制的时候遍历Layer,Layer又会调用自己的SurfaceFlingerConsumer将合适的Buffer更新到纹理中。

SufaceFlinger更新纹理,上一步介绍了如果从BufferQueue中获取Buffer.这一步介绍,如何更新到纹理。
1:首先做判断,是否attach到EGLContext,没有Attach则直接释放当前Buffer。普通Layer默认是Attach到SurfaceFlinger主线程的EGLContext上的。(需要attach的SurfaceView)
2:检查EGL状态和上次是否发生了变化
3:每个slot中的GraphicBuffer都会创建一个EGLImage,保存在GLConsumer的mEglSlots数组中。
4:释放掉旧的buffer
5:保存新的Buffer信息到GLConsumer信息中,等待将Buffer数据填充到openGL纹理中

上面的步骤已经把Buffer从Buffer队列获取到了,也已经将Buffer更新到GLConsumer中,同时也释放掉了旧的Buffer,但是何时填充纹理进行绘制呢?
也是在SurfaceFlinger进行图形合成的过程中,先执行了latchBuffer来更新纹理,后边后依次执行Layer的onDraw方法,进行绘制,Layer的onDraw方法会调用SurfaceFlingerConsumer的bindTextureImage来绑定并填充纹理。

status_t GLConsumer::bindTextureImageLocked() {
    //检查mEglDisplay的状态
    if (mEglDisplay == EGL_NO_DISPLAY) {
        ALOGE("bindTextureImage: invalid display");
        return INVALID_OPERATION;
    }
    //检测openGL是否有错误
    GLenum error;
    while ((error = glGetError()) != GL_NO_ERROR) {
        GLC_LOGW("bindTextureImage: clearing GL error: %#04x", error);
    }

    //绑定当前Layer的纹理信息
    glBindTexture(mTexTarget, mTexName);
    if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT &&
            mCurrentTextureImage == NULL) {
        GLC_LOGE("bindTextureImage: no currently-bound texture");
        return NO_INIT;
    }

    status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
                                                        mCurrentCrop);
    if (err != NO_ERROR) {
        GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
                mEglDisplay, mCurrentTexture);
        return UNKNOWN_ERROR;
    }
    //将Buffer内容填充到纹理
    mCurrentTextureImage->bindToTextureTarget(mTexTarget);
    ......
}

这个步骤将纹理绑定到了EGLContext, 然后调用了glEGLImageTargetTexture2DOES(texTarget,static_cast<GLeglImageOES>(mEglImage));将Buffer内容填充到了纹理中。这样纹理也准备好了,就等SurfaceFlinger进行合成了。

总结:

一个GraphicBuffer缓冲区如何从Producer传递到Consumer,以及Consumer接收到之后如何处理已经分析完成了。过程比较长,做一下简单的总结。

  • 步骤1: 生产者想要绘制图像,必须要有一个GraphicBuffer图像缓冲区,所以必须先调用生产者的dequeueBuffer,从Buffer队列获取一个可用的Buffer。
    获取的时候优先从Buffer队列的FreeBuffer队列查找空闲slot,如果找不到则从FreeSlot队列查找,然后为该Slot分配一个缓冲区。如果Buffer属性发生变化则需要重新分配,Surface中保存的GraphicBuffer也需要释放掉重新从Buffer队列中requestBuffer。
  • 步骤2:生产者绘制完图像后,需要把完成的Buffer放入Buffer队列的mQueue中,等待消费者处理后进行显示。
    在将Buffer放入mQueue的时候,如果队列中最后一个有未来得及处理的Buffer且该Buffer可以被放弃,则直接替换,否则将Buffer放入队列末尾。
  • 步骤3:生产者将Buffer放入队列之后会调用onFrameAvaliable通知消费者SufaceFlingerConsumer,SufaceFlingerConsumer又会通知Layer,Layer会将Buffer信息保存到自己的列表中。然后通知SurfaceFlinger进行更新。
  • 步骤4:SurfaceFlinger更新步骤会遍历mLayerSortByZ列表,依次处理所有的Layer,此时会调用Layer的latchBuffer来更新Layer对应的纹理。
    更新Layer纹理,首先调用acquireBuffer从Buffer队列获取Buffer,获取Buffer会考虑Layer预期显示时间等条件,获取合适的Buffer,放弃来不及显示的Buffer。
    然后判断获取的Buffer是否符合条件,不符合条件则拒绝更新。
    最后将获取的Buffer信息更新到GLConsumer中,然后释放掉旧的Buffer,就的Buffer重新放回队列,等待生产者dequeue。
  • 步骤5:SurfaceFlinger在图像合成的过程中,调用依次Layer的onDraw方法填充纹理,此时会调用SurfaceFlingerConsumer的方法,将上一步保存的图像信息填充到纹理中,等待合成。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,843评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,538评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,187评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,264评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,289评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,231评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,116评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,945评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,367评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,581评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,754评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,458评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,068评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,692评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,842评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,797评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,654评论 2 354

推荐阅读更多精彩内容