Android P 显示流程分析---界面刷新

Posted Give.Me.Five

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android P 显示流程分析---界面刷新相关的知识,希望对你有一定的参考价值。

上篇分析完了setUpHWComposer(), 这篇就来分析实际图层合成部分了。

void SurfaceFlinger::doComposition() 
    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));
			//重画所有的脏区域
            // repaint the framebuffer (if needed)
            doDisplayComposition(hw, dirtyRegion);

            hw->dirtyRegion.clear();
            hw->flip();
        
    
    //发送Framebuffer
    postFramebuffer();

dirtyRegion(hw->getDirtyRegion(repaintEverything))

找到发生变化的区域

Region DisplayDevice::getDirtyRegion(bool repaintEverything) const 
    Region dirty;
    //这里的repainEverything = 0
    if (repaintEverything) 
        dirty.set(getBounds());
     else 
        const Transform& planeTransform(mGlobalTransform);
        dirty = planeTransform.transform(this->dirtyRegion);
        dirty.andSelf(getBounds());
    
    return dirty;

//确实显示区域的上下左右
FloatRect Transform::transform(const FloatRect& bounds) const

    vec2 lt(bounds.left, bounds.top);
    vec2 rt(bounds.right, bounds.top);
    vec2 lb(bounds.left, bounds.bottom);
    vec2 rb(bounds.right, bounds.bottom);

    lt = transform(lt);
    rt = transform(rt);
    lb = transform(lb);
    rb = transform(rb);

    FloatRect r;
    r.left = min(lt[0], rt[0], lb[0], rb[0]);
    r.top = min(lt[1], rt[1], lb[1], rb[1]);
    r.right = max(lt[0], rt[0], lb[0], rb[0]);
    r.bottom = max(lt[1], rt[1], lb[1], rb[1]);

    return r;

doDisplayComposition(hw, dirtyRegion)

上面获取到了显示区域,现在需要做显示合成了

void SurfaceFlinger::doDisplayComposition(
        const sp<const DisplayDevice>& displayDevice,
        const Region& inDirtyRegion)

    // We only need to actually compose the display if:
    // 1) It is being handled by hardware composer, which may need this to
    //    keep its virtual display state machine in sync, or
    // 2) There is work to be done (the dirty region isn't empty)
    bool isHwcDisplay = displayDevice->getHwcDisplayId() >= 0;
    if (!isHwcDisplay && inDirtyRegion.isEmpty()) 
        ALOGV("Skipping display composition");
        return;
    

    ALOGV("doDisplayComposition");
    //设置渲染的区域,对区域做渲染的初始化,如颜色,区域大小等
    if (!doComposeSurfaces(displayDevice)) return;

	//交互分区
    // swap buffers (presentation)
    displayDevice->swapBuffers(getHwComposer());

这个里面做了两件事,一个是区域的初始化,主要是针对Render的。第二个是交互分区,这个需要重点分析下,分区是如何切换的

void DisplayDevice::swapBuffers(HWComposer& hwc) const 
    if (hwc.hasClientComposition(mHwcDisplayId) || hwc.hasFlipClientTargetRequest(mHwcDisplayId)) 
    	//surface 切换buffer
        mSurface->swapBuffers();
    
	//为下一个buffer做准备
    status_t result = mDisplaySurface->advanceFrame();
    if (result != NO_ERROR) 
        ALOGE("[%s] failed pushing new frame to HWC: %d",
                mDisplayName.string(), result);
    

mSurface->swapBuffers() 也就是调用opengl里的最终送显函数eglSwapBuffers(mEGLDisplay, mEGLSurface)。
重点来看看如何为下一个buffer做准备的

status_t FramebufferSurface::advanceFrame() 
    uint32_t slot = 0;
    sp<GraphicBuffer> buf;
    sp<Fence> acquireFence(Fence::NO_FENCE);
    Dataspace dataspace = Dataspace::UNKNOWN;
    //获取下一个槽位,buffer,fence,以及数据空间
    status_t result = nextBuffer(slot, buf, acquireFence, dataspace);
    mDataSpace = dataspace;
    if (result != NO_ERROR) 
        ALOGE("error latching next FramebufferSurface buffer: %s (%d)",
                strerror(-result), result);
    
    return result;

继续分析nextBuffer

status_t FramebufferSurface::nextBuffer(uint32_t& outSlot,
        sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence,
        Dataspace& outDataspace) 
    Mutex::Autolock lock(mMutex);

    BufferItem item;
    //获取下一个Buffer
    status_t err = acquireBufferLocked(&item, 0);
    if (err == BufferQueue::NO_BUFFER_AVAILABLE) 
    	//如果没有可用buff,从缓存中获取
        mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
                &outSlot, &outBuffer);
        return NO_ERROR;
     else if (err != NO_ERROR) 
        ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err);
        return err;
    

    // If the BufferQueue has freed and reallocated a buffer in mCurrentSlot
    // then we may have acquired the slot we already own.  If we had released
    // our current buffer before we call acquireBuffer then that release call
    // would have returned STALE_BUFFER_SLOT, and we would have called
    // freeBufferLocked on that slot.  Because the buffer slot has already
    // been overwritten with the new buffer all we have to do is skip the
    // releaseBuffer call and we should be in the same state we'd be in if we
    // had released the old buffer first.
    if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT &&
        item.mSlot != mCurrentBufferSlot) 
        mHasPendingRelease = true;
        mPreviousBufferSlot = mCurrentBufferSlot;
        mPreviousBuffer = mCurrentBuffer;
    
    mCurrentBufferSlot = item.mSlot;
    mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer;
    mCurrentFence = item.mFence;

    outFence = item.mFence;
    mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
            &outSlot, &outBuffer);
    outDataspace = static_cast<Dataspace>(item.mDataSpace);
    //设置目标的显示buffer
    status_t result =
            mHwc.setClientTarget(mDisplayType, outSlot, outFence, outBuffer, outDataspace);
    if (result != NO_ERROR) 
        ALOGE("error posting framebuffer: %d", result);
        return result;
    

    return NO_ERROR;

这里主要做了三件事,获取下一次显示的buffer, 将此buffer 做一个缓存处理,将buffer相关信息送到hwc中,设置为下一次目标。
往下看看获取buffer的过程:

status_t ConsumerBase::acquireBufferLocked(BufferItem *item,
        nsecs_t presentWhen, uint64_t maxFrameNumber) 
    if (mAbandoned) 
        CB_LOGE("acquireBufferLocked: ConsumerBase is abandoned!");
        return NO_INIT;
    
	//从消费者获取可以用buffer
    status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber);
    if (err != NO_ERROR) 
        return err;
    

    if (item->mGraphicBuffer != NULL) 
        if (mSlots[item->mSlot].mGraphicBuffer != NULL) 
            freeBufferLocked(item->mSlot);
        
        mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
    

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

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

    return OK;

这里是从消费者的buffer队列中获取 到buffer, 这里要引出一个生产者–消费者模式的buffer队列。下一篇来重点讲生产者–消费者模式的Buffer对列。

postFramebuffer()

void SurfaceFlinger::postFramebuffer()

    ATRACE_CALL();
    ALOGV("postFramebuffer");

    const nsecs_t now = systemTime();
    mDebugInSwapBuffers = now;
	//遍历所有显示屏
    for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) 
        auto& displayDevice = mDisplays[displayId];
        if (!displayDevice->isDisplayOn()) 
            continue;
        
        const auto hwcId = displayDevice->getHwcDisplayId();
        if (hwcId >= 0) 
            getBE().mHwc->presentAndGetReleaseFences(hwcId);
        
        //回调onSwapBuffersCompleted()
        displayDevice->onSwapBuffersCompleted();
        //重新设置当前的Surface
        displayDevice->makeCurrent();
        //按照Z轴显示顺序来遍历图层
        for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) 
            // The layer buffer from the previous frame (if any) is released
            // by HWC only when the release fence from this frame (if any) is
            // signaled.  Always get the release fence from HWC first.
            auto hwcLayer = layer->getHwcLayer(hwcId);
            sp<Fence> releaseFence = getBE().mHwc->getLayerReleaseFence(hwcId, hwcLayer);

            // If the layer was client composited in the previous frame, we
            // need to merge with the previous client target acquire fence.
            // Since we do not track that, always merge with the current
            // client target acquire fence when it is available, even though
            // this is suboptimal.
            if (layer->getCompositionType(hwcId) == HWC2::Composition::Client) 
                releaseFence = Fence::merge("LayerRelease", releaseFence,
                        displayDevice->getClientTargetAcquireFence());
            
			//根据释放的Fence来回调onLayerDisplayed
            layer->onLayerDisplayed(releaseFence);
        

        // We've got a list of layers needing fences, that are disjoint with
        // displayDevice->getVisibleLayersSortedByZ.  The best we can do is to
        // supply them with the present fence.
        if (!displayDevice->getLayersNeedingFences().isEmpty()) 
            sp<Fence> presentFence = getBE().mHwc->getPresentFence(hwcId);
            for (auto& layer : displayDevice->getLayersNeedingFences()) 
            	//提供当前Fence给当前需要Fence的图层
                layer->onLayerDisplayed(presentFence);
            
        

        if (hwcId >= 0) 
            getBE().mHwc->clearReleaseFences(hwcId);
        
    

    mLastSwapBufferTime = systemTime() - now;
    mDebugInSwapBuffers = 0;

    // |mStateLock| not needed as we are on the main thread
    if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) 
        uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
        if (flipCount % LOG_FRAME_STATS_PERIOD == 0) 
            logFrameStats();
        
    

以上是关于Android P 显示流程分析---界面刷新的主要内容,如果未能解决你的问题,请参考以下文章

Android P 显示流程分析---EventThread MessageQueue 交互分析

Android P 显示流程分析---获取显示屏配置

Android P 显示流程---Display设备初始化过程分析

Android P 显示流程分析--- buffer的生产消费者模式

Android P 显示流程分析--- buffer的生产消费者模式

Android Q 基站刷新接口源码分析 & 适配双卡手机基站刷新逻辑