首页 > 其他分享 >Android SurfaceFlinger——Vsync信号发送(五十二)

Android SurfaceFlinger——Vsync信号发送(五十二)

时间:2024-08-08 08:58:42浏览次数:8  
标签:Vsync lock void SurfaceFlinger VSync cpp setVsyncEnabled Android Scheduler

        通过上一篇文章我们创建了一个 EventThread 线程,并且它持有了 SurfaceFlinger 中 resyncWithRateLimit() 方法的指针。这里我们主要来看一下 EventThread 对信号的处理。

一、发送Vsync信号

        当 SurfaceFlinger 执行完 queueBuffer() 方法之后,通过 onFrameAvailable 又会回调到 SurfaceFlinger 中的 commit() 方法中。

1、SurfaceFlinger.cpp

源码位置:/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

commit

bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime)
        FTL_FAKE_GUARD(kMainThreadContext) {
    ……
    if (mSetActiveModePending) {
        // 检查是否有待处理的帧
        if (framePending) {
            mScheduler->scheduleFrame();
            return false;
        }

        mSetActiveModePending = false;
        {
            Mutex::Autolock lock(mStateLock);
            updateInternalStateWithChangedMode();
        }
    }

    // 检查是否有待处理的帧
    if (framePending) {
        if ((hwcFrameMissed && !gpuFrameMissed) || mPropagateBackpressureClientComposition) {
            scheduleCommit(FrameHint::kNone);
            return false;
        }
    }
    ……
}

        这里多次检查是否有待处理的帧,如果有最终都会调用 mScheduler->scheduleFrame() 来尝试调度一个新帧。

scheduleCommit

void SurfaceFlinger::scheduleCommit(FrameHint hint) {
    if (hint == FrameHint::kActive) {
        // 重置空闲计时器
        mScheduler->resetIdleTimer();
    }
    // 通知即将更新显示
    mPowerAdvisor->notifyDisplayUpdateImminent();
    // 试调度一个新帧
    mScheduler->scheduleFrame();
}

        这里最终同样是来调度一个新的帧提交,上面的 mScheduler 继承自 MessageQueue。

2、MessageQueue.cpp

源码位置:/frameworks/native/services/surfaceflinger/Scheduler/MessageQueue.cpp

scheduleFrame

// 设置事件注入器
void MessageQueue::setInjector(sp<EventThreadConnection> connection) {
    ……
    mInjector.connection = std::move(connection);
}

void MessageQueue::scheduleFrame() {
    ……
    {
        std::lock_guard lock(mInjector.mutex);
        if (CC_UNLIKELY(mInjector.connection)) {
            // 请求下一个VSync信号
            mInjector.connection->requestNextVsync();
            return;
        }
    }
    ……
}

        这里通过 EventThreadConnection 来请求 VSync 信号,从而调度新的帧提交。

3、EventThread.cpp

源码位置:/frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp

        看到这里,是不是就进入到前面创建的信号处理线程了,该类启动一个专门用于处理 VSync 信号的线程。其中 EventThreadConnection 是 EventThread 的内部类。

EventThreadConnection::requestNextVsync

binder::Status EventThreadConnection::requestNextVsync() {
    ATRACE_CALL();
    mEventThread->requestNextVsync(this);
    return binder::Status::ok();
}

        这里调用了 EventThread 的 requestNextVsync() 函数。

EventThread::requestNextVsync

void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
    if (connection->resyncCallback) {
        connection->resyncCallback();
    }

    std::lock_guard<std::mutex> lock(mMutex);

    if (connection->vsyncRequest == VSyncRequest::None) {
        connection->vsyncRequest = VSyncRequest::Single;
        // 通知所有等待线程
        mCondition.notify_all();
    } else if (connection->vsyncRequest == VSyncRequest::SingleSuppressCallback) {
        connection->vsyncRequest = VSyncRequest::Single;
    }
}

        该函数主要用于处理与垂直同步(vsync)相关的请求。这里的 resyncCallback() 函数是在创建 EventThreadConnection 时以参数的形式传入的,我们来看一下。

createEventConnection

sp<EventThreadConnection> EventThread::createEventConnection(ResyncCallback resyncCallback,
        ISurfaceComposer::EventRegistrationFlags eventRegistration) const {
    return new EventThreadConnection(const_cast<EventThread*>(this),
            IPCThreadState::self()->getCallingUid(), std::move(resyncCallback), eventRegistration);
}

        而该创建函数是在 MessageQueue 的子类 Scheduler 中调用的。

4、Scheduler.cpp

源码位置:/frameworks/native/services/surfaceflinger/Scheduler/Scheduler.cpp

createConnectionInternal

sp<EventThreadConnection> Scheduler::createConnectionInternal(EventThread* eventThread, 
        ISurfaceComposer::EventRegistrationFlags eventRegistration) {
    return eventThread->createEventConnection([&] { resync(); }, eventRegistration);
}

        所以上面的 resyncCallback 应该就是这里的 resync() 函数。

resync

void Scheduler::resync() {
    // 两次重新同步之间需要忽略的最短时间间隔,这里是750毫秒
    static constexpr nsecs_t kIgnoreDelay = ms2ns(750);

    // 获取当前系统时间
    const nsecs_t now = systemTime();
    // 获取并更新上次重新同步的时间
    const nsecs_t last = mLastResyncTime.exchange(now);

    // 如果当前时间和上次重新同步时间之间的差值大于kIgnoreDelay,表示需要重新同步
    if (now - last > kIgnoreDelay) {
        // 获取当前的刷新率
        const auto refreshRate = [&] {
            // 获取当前活动模式的刷新率(FPS)
            std::scoped_lock lock(mRefreshRateConfigsLock);
            return mRefreshRateConfigs->getActiveMode()->getFps();
        }();
        // 重新同步,传入false表示不需要强制重新同步
        resyncToHardwareVsync(false, refreshRate);
    }
}

        该函数主要功能是重新同步系统时间与硬件 VSync 信号,同时根据需要适当地调整了重新同步的频率。

void Scheduler::resyncToHardwareVsync(bool makeAvailable, Fps refreshRate) {
    {
        std::lock_guard<std::mutex> lock(mHWVsyncLock);
        if (makeAvailable) { // 硬件VSync可用
            mHWVsyncAvailable = makeAvailable;
        } else if (!mHWVsyncAvailable) { // 硬件VSync不可用
            // 取消重新同步尝试
            return;
        }
    }

    // 设置VSync周期
    setVsyncPeriod(refreshRate.getPeriodNsecs());
}

        该函数不仅确保了在硬件 VSync 可用的情况下进行重新同步,还根据需要适当地设置了 VSync 周期。

void Scheduler::setVsyncPeriod(nsecs_t period) {
    if (period <= 0) return;

    std::lock_guard<std::mutex> lock(mHWVsyncLock);
    // 开始周期转换过程,设置新的VSync周期
    mVsyncSchedule->getController().startPeriodTransition(period);

    if (!mPrimaryHWVsyncEnabled) { // 未启用
        // 重置VSync追踪模型
        mVsyncSchedule->getTracker().resetModel();
        // 启用VSync
        mSchedulerCallback.setVsyncEnabled(true);
        // 主硬件VSync现在已启用
        mPrimaryHWVsyncEnabled = true;
    }
}

        该函数不仅确保了 VSync 周期的正确设置,还根据需要启用了硬件 VSync。 这里主要的操作有两个:

startPeriodTransition:设置新的 VSync 周期。

setVsyncEnabled:启用 VSync。

         下面来分别看一下这两个信号处理的调用流程。

二、信号处理

1、设置VSync周期

        上面设置信号周期的 mVsyncSchedule 就是 VsyncSchedule。这里看一下对应的 getController 函数。

源码位置:/frameworks/native/services/surfaceflinger/Scheduler/VsyncSchedule.h

getController

class VsyncController;

VsyncController& getController() { return *mController; }

        可以看到 getController() 函数返回的是 VsyncController,而 VSyncReactor 又继承了 VsyncController,所以上面 mVsyncSchedule->getController().startPeriodTransition() 最终调用的其实就是 VSyncReactor 中的对应函数。

VSyncReactor.cpp

源码位置:/frameworks/native/services/surfaceflinger/Scheduler/VSyncReactor.cpp

void VSyncReactor::startPeriodTransition(nsecs_t period) {
    ATRACE_INT64("VSR-setPeriod", period);
    std::lock_guard lock(mMutex);
    // 重置最后的硬件VSync时间
    mLastHwVsync.reset();

    if (!mSupportKernelIdleTimer && period == mTracker.currentPeriod()) {
        // 结束周期转换过程,无需实际转换周期
        endPeriodTransition();
        // 取消忽略呈现围栏
        setIgnorePresentFencesInternal(false);
        mMoreSamplesNeeded = false;
    } else {
        // 开始周期转换过程
        startPeriodTransitionInternal(period);
    }
}

        这里开始 VSync 周期的转换过程,调用 startPeriodTransitionInternal() 函数。

startPeriodTransitionInternal 
void VSyncReactor::startPeriodTransitionInternal(nsecs_t newPeriod) {
    ATRACE_CALL();
    // 周期转换正在进行中
    mPeriodConfirmationInProgress = true;
    // 新的周期值
    mPeriodTransitioningTo = newPeriod;
    // 需要收集更多的样本数据来确认新的周期
    mMoreSamplesNeeded = true;
    // 忽略呈现围栏,有助于避免在周期转换期间出现干扰。
    setIgnorePresentFencesInternal(true);
}

        这里 VSync 周期转换过程的正确开始,并设置了必要的标志来支持周期转换的完成。

setIgnorePresentFencesInternal
void VSyncReactor::setIgnorePresentFencesInternal(bool ignore) {
    mInternalIgnoreFences = ignore;
    // 更新内部状态
    updateIgnorePresentFencesInternal();
}

        该函数用于设置是否忽略呈现围栏。

updateIgnorePresentFencesInternal
void VSyncReactor::updateIgnorePresentFencesInternal() {
    if (mExternalIgnoreFences || mInternalIgnoreFences) {
        // 清空未触发的围栏列表
        mUnfiredFences.clear();
    }
}

        这里根据外部和内部的忽略标志来更新未触发的围栏列表。

2、启用VSync

        上面的 mSchedulerCallback 是 ISchedulerCallback,而 SurfaceFlinger 又继承了该类,所以这里其实调用的就是 SurfaceFlinger 中的 setVsyncEnabled 函数。

setVsyncEnabled

void SurfaceFlinger::setVsyncEnabled(bool enabled) {
    ATRACE_CALL();

    // 调度一个任务,确保在主线程上执行
    static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
        mHWCVsyncPendingState = enabled ? hal::Vsync::ENABLE : hal::Vsync::DISABLE;

        // 默认显示设备是否已打开电源
        if (const auto display = getDefaultDisplayDeviceLocked(); display && display->isPoweredOn()) {
            // 设置硬件VSync的启用状态
            setHWCVsyncEnabled(display->getPhysicalId(), mHWCVsyncPendingState);
        }
    }));
}

        该函数主要功能是在主线程上设置硬件 VSync 的启用状态。

setHWCVsyncEnabled

源码位置:/frameworks/native/services/surfaceflinger/SurfaceFlinger.h

void setHWCVsyncEnabled(PhysicalDisplayId id, hal::Vsync enabled) {
    mLastHWCVsyncState = enabled;
    getHwComposer().setVsyncEnabled(id, enabled);
}

        这里调用了 HWComposer 中的 setVsyncEnabled() 函数。

HWComposer.cpp  

源码位置:/frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp 

std::unique_ptr<HWC2::Display> hwcDisplay;

void HWComposer::setVsyncEnabled(PhysicalDisplayId displayId, hal::Vsync enabled) {
    RETURN_IF_INVALID_DISPLAY(displayId);
    auto& displayData = mDisplayData[displayId];
    ……
    auto error = displayData.hwcDisplay->setVsyncEnabled(enabled);
    displayData.vsyncEnabled = enabled;
    ……
}

        这里将硬件 VSync 的启用状态能够在指定的物理显示设备上正确地设置。

HWC2.cpp

源码位置:/frameworks/native/services/surfaceflinger/DisplayHardware/HWC2.cpp

Error Display::setVsyncEnabled(Vsync enabled)
{
    auto intEnabled = static_cast<Hwc2::IComposerClient::Vsync>(enabled);
    auto intError = mComposer.setVsyncEnabled(mId, intEnabled);
    return static_cast<Error>(intError);
}

AidlComposerHal.cpp 

源码位置:/frameworks/native/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp

Error AidlComposer::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) {
    const bool enableVsync = enabled == IComposerClient::Vsync::ENABLE;
    const auto status =
            mAidlComposerClient->setVsyncEnabled(translate<int64_t>(display), enableVsync);
    if (!status.isOk()) {
        ALOGE("setVsyncEnabled failed %s", status.getDescription().c_str());
        return static_cast<Error>(status.getServiceSpecificError());
    }
    return Error::NONE;
}

        这里接下来调用到 Hal 层,并最终调用到 硬件合成器(HWC),调用对应的预加载接口,这里就不做过多介绍了。

标签:Vsync,lock,void,SurfaceFlinger,VSync,cpp,setVsyncEnabled,Android,Scheduler
From: https://blog.csdn.net/c19344881x/article/details/140875529

相关文章

  • Android SurfaceFlinger——Fence流转状态(五十)
            明白了fence的基本原理,我们可以进一步的探索整个SurfaceFlinger的中fence在其中处于什么角色。一、流转状态        从启动到屏幕的第一帧的渲染,fence是不会有任何效果的。因为此时fence还没有经过hwc_set给fence进行赋值。但是到了第......
  • Android Qcom USB Driver学习(一)
    该系列文章总目录链接与各部分简介:AndroidQcomUSBDriver学习(零)USB接口类型Android终端上常用的USB接口:TypeC(现在的主流),MicroB(以前的设备)一、TypeCHardwareInterfaceUSB-C引脚和功能指南一文读懂USBTypeC与USB-…TypeC引脚定义USB-C(USBType-C)规范的简单介绍......
  • Android 是如何进行内存管理的
    目录1.垃圾回收(GarbageCollection)2.内存分配3.内存泄漏检测4.内存优化5.内存抖动(MemoryChurn)6.内存警告(MemoryWarning)7.内存分页(MemoryPaging)8.内存分段(MemorySegmentation)9.内存压缩(MemoryCompaction)10.内存分区(MemoryPartitionin......
  • Android Qcom USB Driver学习(零)
    该系列文章总目录链接与各部分简介:AndroidQcomUSBDriver学习(零)文章标题文章链接文章简介AndroidQcomUSBDriver学习(零)https://blog.csdn.net/qq_40405527/article/details/125460598本章主要学习博客各个标题的链接与简介AndroidQcomUSBDriver学习(......
  • Android开发基础06-Android项目结构
    详细介绍Android项目结构Android开发过程中,高效、清晰的项目结构是成功的关键。理解并合理组织项目结构,有助于提高代码的可维护性和团队协作的效率。目录概览一个典型的Android项目目录结构如下:MyApplication/├──app/│├──build/│├──libs/│├......
  • Java计算机毕业设计基于Android的公交线路状态查询系统(开题报告+源码+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着城市化进程的加速,公共交通系统成为了城市居民日常出行不可或缺的一部分。然而,传统的公交线路查询方式往往依赖于纸质地图、公交站牌或电话查询,这......
  • Android开发基础04-Java 和 Kotlin
    引言Java和Kotlin是两种主要用于Android开发的编程语言。理解它们的基本概念、特点、优缺点及常见用法,对Android开发者来说非常重要。1.Java基本概念Java是一种面向对象、跨平台的编程语言,于1995年由SunMicrosystems(现为Oracle)发布。它的设计理念是“WriteOnce,Ru......
  • Android开发基础02-零基础学习Android指南
    学习路线1.理解Android开发基础1.1理解Android平台架构先从高层次上了解Android操作系统的架构,包括应用层、应用框架层、库和Android运行时、Linux内核。了解这些层次及其作用,会帮你更好地理解Android的工作原理。1.2学习Java乐Kotlin语言Java和Kotlin......
  • android源码编译
    搭建编译环境Ubuntu12.04更新源debhttp://old-releases.ubuntu.com/ubuntuprecisemainuniverserestrictedmultiversedebhttp://old-releases.ubuntu.com/ubuntuprecise-securityuniversemainmultiverserestricteddebhttp://old-releases.ubuntu.com/ubuntupre......
  • 记一次 Android 自定义相机拍照奔溃bug事件
    最近在开发一个美颜的相机功能,需要自定义抓取相机回调的数,生成照片并保存到相册,需要自定义保存照片。相机开始使用时没有任何问题,测试拍照几次后突然奔溃,跟踪代码日志发现是图片保存失败,同样的代码,同样的逻辑,正常使用很多次以后才奔溃报错,根据日志找到报错的位置,ContentValue......