当前位置: 首页 > news >正文

Android SurfaceFlinger——信号同步原理(五十一)

        经过前面系列文章的学习,我们的已经理解了 SurfaceFlinger 运行机制以及同步机制,但是SurfaceFlinger 又是以什么方法是把需要刷新的信号发送给 App 进程的。

一、VSync简介

        垂直同步(Vertical Synchronization,简称 VSync)是一种用于同步视频信号和显示设备刷新率的技术,以确保视频帧的显示与屏幕的刷新周期相匹配。VSync 对于防止屏幕撕裂(tearing)、保证图像的连贯性和减少输入延迟非常重要。

VSync信号

        VSync 信号就是在垂直消隐期产生的一个脉冲信号,用来指示显示器已经完成了当前帧的显示,并且准备好接收下一帧的数据。这个信号对于视频源(如显卡)来说是一个重要的同步信号,它告诉视频源何时可以开始传输下一帧图像数据。

VSync作用

        在图形渲染中,VSync的作用是将GPU的帧渲染速率限制在显示器的刷新率之内。如果没有VSync,GPU可能会在任意时刻将帧发送给显示器,这可能导致屏幕撕裂现象——即屏幕上半部分显示的是前一帧的内容,而下半部分显示的是新帧的内容,因为两帧是在同一垂直刷新周期内交错显示的。

屏幕刷新原理

        显示器通过逐行扫描的方式来显示图像。每一帧图像由一系列的水平扫描线组成,这些扫描线在垂直方向上依次被点亮。当所有的扫描线完成一次刷新后,显示器会进入一个短暂的垂直消隐期(Vertical Blanking Interval,VBI),在这个期间,显示器不会显示任何图像,而是重新定位电子束,准备下一次的扫描。

VSync工作原理

        当启用 VSync 时,GPU 会等待下一个 VSync 信号到达,然后再将渲染完成的帧提交给显示器。这意味着 GPU 的帧渲染速率将被同步到显示器的刷新率,从而避免屏幕撕裂。然而,这也可能引入额外的延迟,因为 GPU 可能需要等待直到下一个 VSync 信号才开始渲染下一帧。

        在现代的计算机系统中,VSync 信号的生成和处理通常是由显示驱动程序和硬件(如显卡)协同完成的。例如,在 Android 系统中,VSync 信号是由 DispSync 线程根据硬件控制器(HWC)产生的 VSync 信号进行采样和建模,然后输出软件 VSync 信号(SW_VSYNC),这个信号再根据 SurfaceFlinger 和应用程序的相位偏移进行调整,分别输出给 SurfaceFlinger 和应用程序。

        总之,VSync 是一种确保视频输出与显示设备刷新率同步的技术,它通过控制 GPU 的帧提交时间来防止屏幕撕裂并保证视觉效果的平滑性。

二、源码分析

1、SurfaceFlinger.cpp

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

initScheduler

scheduler::ConnectionHandle mAppConnectionHandle;
scheduler::ConnectionHandle mSfConnectionHandle;void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) {……const auto configs = mVsyncConfiguration->getCurrentConfigs();const nsecs_t vsyncPeriod = currRefreshRate.getPeriodNsecs();// 创建应用连接mAppConnectionHandle = mScheduler->createConnection("app", mFrameTimeline->getTokenManager(),/*workDuration=*/configs.late.appWorkDuration,/*readyDuration=*/configs.late.sfWorkDuration,impl::EventThread::InterceptVSyncsCallback());// 创建 SurfaceFlinger 连接mSfConnectionHandle = mScheduler->createConnection("appSf", mFrameTimeline->getTokenManager(),/*workDuration=*/std::chrono::nanoseconds(vsyncPeriod),/*readyDuration=*/configs.late.sfWorkDuration, [this](nsecs_t timestamp) {mInterceptor->saveVSyncEvent(timestamp);});// 初始化 VSyncmScheduler->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(),configs.late.sfWorkDuration);……
}

        该函数主要初始化与调度器 (mScheduler) 的连接,用于处理应用和 SurfaceFlinger 本身的 VSync 事件。以确保应用和 SurfaceFlinger 自身能够正确地处理 VSync 事件,从而实现流畅的画面更新。

2、Scheduler.cpp

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

createConnection

ConnectionHandle Scheduler::createConnection(const char* connectionName, frametimeline::TokenManager* tokenManager,std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, impl::EventThread::InterceptVSyncsCallback interceptCallback) {// 创建VSync源auto vsyncSource = makePrimaryDispSyncSource(connectionName, workDuration, readyDuration);// 创建VSync节流回调,用于控制VSync信号的频率auto throttleVsync = makeThrottleVsyncCallback();// 创建获取VSync周期的函数auto getVsyncPeriod = makeGetVsyncPeriodFunction();// 构建事件线程auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource), tokenManager,std::move(interceptCallback), std::move(throttleVsync), std::move(getVsyncPeriod));// 创建连接句柄return createConnection(std::move(eventThread));
}

        这里从创建基础的同步机制到构建完整的事件处理线程,最终形成一个可以被外部系统使用的连接句柄。并且可以看到,初始化的 EventThread 持有一个十分核心对象 VSyncSource。

makePrimaryDispSyncSource 

std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(const char* name,     std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, bool traceVsync) {return std::make_unique<scheduler::DispSyncSource>(mVsyncSchedule->getDispatch(),mVsyncSchedule->getTracker(), workDuration, readyDuration, traceVsync, name);
}

         可以看到,这里主要是创建并返回一个 VSyncSource,用于生成垂直同步(VSync)信号的源头。

createConnection

ConnectionHandle Scheduler::createConnection(std::unique_ptr<EventThread> eventThread) {// 生成新的连接ID,用于唯一标识创建的连接句柄const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++};ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id);// 内部连接创建auto connection = createConnectionInternal(eventThread.get());std::lock_guard<std::mutex> lock(mConnectionsLock);// 存储连接信息mConnections.emplace(handle, Connection{connection, std::move(eventThread)});return handle;
}

        该函数不仅创建了一个唯一的连接句柄,还将其与一个具体的 EventThread 实例关联起来。

createConnectionInternal

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

        这里利用给定的 EventThread 实例创建一个内部的事件连接(EventThreadConnection)。 

3、EventThread.cpp

        EventThread 扮演了处理 VSync(垂直同步)信号的核心角色。SurfaceFlinger 是负责窗口和显示合成的主要服务,它确保所有应用程序的帧在屏幕上正确且及时地呈现。

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

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

        该函数不仅创建了 EventThreadConnection 实例,还初始化了它的关键属性,如事件线程的引用、调用者的 UID、重新同步的回调以及事件注册的标志。这使得 EventThreadConnection 能够作为接口,让外部组件与事件线程进行交互,同时遵循预定的事件处理规则和策略。 

EventThread的角色

        在 SurfaceFlinger 中,存在两种类型的 EventThread:

  • App 端的 EventThread:负责监听应用程序请求的 VSync 信号,通常用于游戏或动画应用,需要精确的时间同步来保证流畅的视觉效果。
  • SurfaceFlinger 端的 EventThread:直接与硬件交互,接收来自显示器的 VSync 信号,并将这些信号分发给所有需要同步的应用程序或系统组件。

VSync信号处理

  • 硬件 VSync 信号接收:硬件层(HAL)的 EventThread(例如 SDM_EventThread)从显示控制器接收原始的 VSync 信号。
  • 信号分发:这些信号被传递给 SurfaceFlinger 的 EventThread,它使用 DispSync 机制来同步这些信号。
  • 信号处理:EventThread 通过 DispSyncSource 类来处理 VSync 信号,这涉及到计算和调整 VSync 周期,以适应不同应用的需求。
  • 信号分发给客户端:EventThread 将 VSync 信号分发给注册了 VSync 监听器的所有客户端,包括应用程序和其他系统服务。

        EventThread 通常会维护一个事件队列,用于存储接收到的 VSync 事件。它会定期检查事件队列,并唤醒等待 VSync 信号的线程。EventThread 可能还会实现一些优化,比如 VSync 信号的节流,以减少不必要的 CPU 唤醒和功耗。

        在代码层面,EventThread 的实现可能涉及多个类和接口,如 DispSyncThread、DispSyncSource 和 EventThreadConnection等,它们共同协作来完成 VSync 信号的接收、处理和分发。

        总之,EventThread 在 SurfaceFlinger 中是 VSync 信号处理的核心,它确保了系统和应用程序能够根据显示器的实际刷新率同步其渲染输出,从而提供平滑和一致的用户体验。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 探索WebKit的奥秘:塑造高效、兼容的现代网页应用
  • maxscript循环中提高性能
  • 记一次对加密后pythonEXP的解密以及分析
  • SS9283403 sqlite3交叉编译并部署到SS928(六)
  • Together规则引擎 金融解决方案
  • 八股文”在实际工作中的作用:敲门砖还是空谈?
  • supermap制作发布二三维地图服务
  • 基于企业微信第三方接口开发,发送朋友圈评论
  • MySQL:数据库权限与角色
  • 单机系统怎么做高可用设计
  • 【强化学习】强化学习的基本概念与应用
  • Linux中为什么要进行对齐分区及其作用
  • maven常用命令与常见问题汇总
  • 【SpringBoot】Web配置之跨域访问
  • 主从备份(复制)
  • 【附node操作实例】redis简明入门系列—字符串类型
  • 【技术性】Search知识
  • JAVA SE 6 GC调优笔记
  • java2019面试题北京
  • k8s如何管理Pod
  • LeetCode刷题——29. Divide Two Integers(Part 1靠自己)
  • vue2.0项目引入element-ui
  • vue-router 实现分析
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 从零到一:用Phaser.js写意地开发小游戏(Chapter 3 - 加载游戏资源)
  • 基于Mobx的多页面小程序的全局共享状态管理实践
  • 基于web的全景—— Pannellum小试
  • 排序算法学习笔记
  • 批量截取pdf文件
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • gunicorn工作原理
  • ​马来语翻译中文去哪比较好?
  • #android不同版本废弃api,新api。
  • #Linux杂记--将Python3的源码编译为.so文件方法与Linux环境下的交叉编译方法
  • #VERDI# 关于如何查看FSM状态机的方法
  • #图像处理
  • (C语言)深入理解指针2之野指针与传值与传址与assert断言
  • (超详细)语音信号处理之特征提取
  • (附源码)ssm码农论坛 毕业设计 231126
  • (九)信息融合方式简介
  • (四)模仿学习-完成后台管理页面查询
  • (学习日记)2024.04.10:UCOSIII第三十八节:事件实验
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • * CIL library *(* CIL module *) : error LNK2005: _DllMain@12 already defined in mfcs120u.lib(dllmodu
  • .NET 6 Mysql Canal (CDC 增量同步,捕获变更数据) 案例版
  • .NET CLR Hosting 简介
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .NET Core/Framework 创建委托以大幅度提高反射调用的性能
  • .Net Winform开发笔记(一)
  • .NET 表达式计算:Expression Evaluator
  • .NET 读取 JSON格式的数据
  • .NetCore实践篇:分布式监控Zipkin持久化之殇
  • .NET大文件上传知识整理
  • ?php echo ?,?php echo Hello world!;?
  • @AliasFor 使用