vsync信号产生与分发
以下分析基于android 4.4代码
vsync信号的产生、分发涉及到以下几个类,先主要了解下他们各自的功能:
HWComposer:产生hardware vsync,post fb
VSyncThread : 如果没有硬件支持,那么通过软件方式模拟hw vsync
DispSync,DispSyncThread: 接受HWComposer的hw vsync信号作为校准,开始模拟产生vsync信号+偏移,并且会不时地进行校准,如postComposition后。
EventControlThread:sf中的一个线程,仅用来控制hw vsync开关
EventThread:负责分发vsync到sf或app
DispSyncSource:EventThread和DispSyncThread的信息传递者, 把vsync信号从DispSyncThread传递到EventThread;同时可以用来设置相位偏移参数。
在4.4之后,vsync信号不再完全由硬件产生,hw vsync信号主要用来做时间校准,vsync信号发生者是DispSyncThread, 当DispSyncThread产生的信号得到校准后,hw vsync会被关闭。
几个问题分析:
1.硬件vsync开启-关闭过程
(1)HWComposer在hwc_composer_device_1中注册回调:
mCBContext->procs.vsync = &hook_vsync;
mHwc->registerProcs(mHwc, &mCBContext->procs);
(2)vsync过来:HWComposer::hook_vsync => HWComposer::vsync
(3)HWComposer::vsync=>mEventHandler.onVSyncReceived(disp, timestamp);
mEventHandler即surfaceflinger
(4)SurfaceFlinger::onVSyncReceived:
needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp); //加入样本,校准mPrimaryDispSync(DispSync),返回是否还需要hwsync
if (needsHwVsync) {
enableHardwareVsync(); //未同步,接续接受hw vsync
} else {
disableHardwareVsync(false); //已同步,关闭hw vsync
}
开启或关闭硬vsync:
SurfaceFlinger::enableHardwareVsync() => mEventControlThread->setVsyncEnabled(true); //sf专门启动了一个线程EventControlThread来开关硬件vsync
2.DispSyncThread 信号的产生:
(1) 在sf类中声明一个成员变量:
class SurfaceFlinger
{
...
DispSync mPrimaryDispSync;
...
}
(2) 构造函数里启动DispSyncThread线程
DispSync::DispSync() {
mThread = new DispSyncThread();
mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
reset();
beginResync();
...
}
(3) 进入DispSyncThread::threadLoop(): 计算vsync周期,调用所有存在mEventListeners的Listener的callback
fireCallbackInvocations()方法中调用callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);
mCallback的类型为DispSync::Callback
(4) mEventListeners的注册通过调用DispSync::addEventListener()
(5) 谁注册成为了vsync事件的监听者? 是DispSyncSource
DispSyncSource继承自DispSync::Callback, 在它setVSysncEnabled(true)中调用:
status_t err = mDispSync->addEventListener(mPhaseOffset,
static_cast<DispSync::Callback*>(this)); //DispSyncSource把自己设为了DispSyncThread vsync信号的监听者 所以vsync消息传到了DispSyncSource中的onDispSyncEvent(nsecs_t when)中:
virtual void onDispSyncEvent(nsecs_t when) {
sp<VSyncSource::Callback> callback;
{
Mutex::Autolock lock(mMutex);
callback = mCallback;
if (mTraceVsync) {
mValue = (mValue + ) % ;
ATRACE_INT("VSYNC", mValue);
}
}
if (callback != NULL) {
callback->onVSyncEvent(when); //又把vsync事件传递到了它自己的mCallback里, 这个mCallback 在EventThread::enableVSyncLocked()中设置, 就是EventThread, 这样vsync传递到了EventThread里
}
}
(6)继续看谁又调用了DispSyncSource::setVSyncEnabled()?
是EventThread::enableVSyncLocked():
void EventThread::enableVSyncLocked() {
if (!mUseSoftwareVSync) {
// never enable h/w VSYNC when screen is off
if (!mVsyncEnabled) {
mVsyncEnabled = true;
mVSyncSource->setCallback(static_cast<VSyncSource::Callback*>(this)); //EventThread设为DispSyncSource的callback
mVSyncSource->setVSyncEnabled(true);
mPowerHAL.vsyncHint(true);
}
}
mDebugVsyncEnabled = true;
}
(7)EventThread::enableVSyncLocked()又被EventThread::waitForEvent()调用
Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
DisplayEventReceiver::Event* event)
{ ...
// Here we figure out if we need to enable or disable vsyncs
if (timestamp && !waitForVSync) {
// we received a VSYNC but we have no clients
// don't report it, and disable VSYNC events
disableVSyncLocked();
} else if (!timestamp && waitForVSync) {
// we have at least one client, so we want vsync enabled
// (TODO: this function is called right after we finish
// notifying clients of a vsync, so this call will be made
// at the vsync rate, e.g. 60fps. If we can accurately
// track the current state we could avoid making this call
// so often.)
enableVSyncLocked();
}
...
}
waitForEvent()的逻辑是:
接到vsync信号,但是当前EventThread中没有请求 vsync 的connection, EventThread向下不再监听vsync
EventThread中有请求 vsync 的connection, EventThread继续监听vsync
总结: vsync传递路径 DispSyncThread => DispSyncSource => EventThread
DispSyncSource: 这个类比较简单,其实就是vsync传递者, 同时负责传递相位偏移phase offset到dispsyncThread。
EventThread: 负责接收vsync, 分发给sf或者app
所以在Sf init中的代码就比较好理解了
// start the EventThread
sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
vsyncPhaseOffsetNs, true);
mEventThread = new EventThread(vsyncSrc);
sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
sfVsyncPhaseOffsetNs, false);
mSFEventThread = new EventThread(sfVsyncSrc);
//上面代码注册了两个vsync信号的监听者, 当vsync产生时,分发给EventThread,这里有两个,一个处理sf,一个处理app mEventQueue.setEventThread(mSFEventThread); // mEventControlThread = new EventControlThread(this);
mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
3. 两个EventThread 线程是怎样把vsync分发给sf和app的?
(1)app与EventThread
EventThread里有一个 class Connection : public BnDisplayEventConnection,
BnDisplayEventConnection 继承自 IDisplayEventConnection
这个接口实现了:
getDataChannel()
setVsyncRate()
requestNextVsync()
App端请求vsync:
app端通过DisplayEventReceiver 中的sp<IDisplayEventConnection> mEventConnection 来requestNextVsync
mEventConnection实际上是BpDisplayEventConnection, 所以requestNextVsync是通过Binder通信从app端传递到EventThread并由它来处理。
同时通过mEventConnection->getDataChannel(); 保存一个BitTube类型的mDataChannel。
在EventThread端:
app调用createEventConnection创建DisplayEventConnection时,EventThread将这个connection注册到它的mDisplayEventConnections集合里
当vsync过来时,通知所有connection
App端接受vsync是通过建立连接时保存的那个BitTube:
//file:android_view_DisplayEventReceiver.cpp
status_t NativeDisplayEventReceiver::initialize() {
status_t result = mReceiver.initCheck();
f (result) {
ALOGW("Failed to initialize display event receiver, status=%d", result);
return result;
} int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), , ALOOPER_EVENT_INPUT, // 监听BitTube的fd,有数据时,调用handler
this, NULL);
if (rc < ) {
return UNKNOWN_ERROR;
}
return OK;
}
所以app接受vsync信号是通过监听BitTube的fd, BitTube底层是通过socket实现。
(2) sf与EventThread
SurfaceFlinger::init()中调用mEventQueue.setEventThread(mSFEventThread);
void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
{
mEventThread = eventThread;
mEvents = eventThread->createEventConnection();
mEventTube = mEvents->getDataChannel();
mLooper->addFd(mEventTube->getFd(), , ALOOPER_EVENT_INPUT,
MessageQueue::cb_eventReceiver, this);
}
在sf进程中直接监听BitTube的fd,当有vsync过来时, 直接由SF的MessageQueue处理
vsync信号产生与分发的更多相关文章
- Android 4.4(KitKat)中VSync信号的虚拟化
原文地址:http://blog.csdn.net/jinzhuojun/article/details/17293325 Android 4.1(Jelly Bean)引入了Vsync(Vertic ...
- 关于 视频同步vsync 信号在不同一时候钟域採样问题
今天调试 视频 4k(3840 x 1920)的vsync信号(时钟为 297Mhz) 进入 170Mhz 的时钟域, 发现输出来的信号信号抖动特别厉害.后来才发现这是不同一时候钟域 造成的影响. 快 ...
- Android 12(S) 图像显示系统 - SurfaceFlinger之VSync-上篇(十六)
必读: Android 12(S) 图像显示系统 - 开篇 一.前言 为了提高Android系统的UI交互速度和操作的流畅度,在Android 4.1中,引入了Project Butter,即&quo ...
- android Gui系统之SurfaceFlinger(4)---Vsync(1)
8.Vsync 8.1概论 VSYNC(Vertical Synchronization)是一个相当古老的概念,对于游戏玩家,它有一个更加大名鼎鼎的中文名字—-垂直同步. “垂直同步(vsync)”指 ...
- Android Vsync 原理浅析
Preface Android中,Client测量和计算布局,SurfaceFlienger(server)用来渲染绘制界面,client和server的是通过匿名共享内存(SharedClient) ...
- Celery-4.1 用户指南: Signals (信号)
基础 有多种类型的事件可以触发信号,你可以连接到这些信号,使得在他们触发的时候执行操作. 连接到 after_task_publish 信号的示例: from celery.signals impor ...
- Android 显示系统:Vsync机制
一.Vsync简介: 屏幕的刷新过程是每一行从左到右(行刷新,水平刷新,Horizontal Scanning),从上到下(屏幕刷新,垂直刷新,Vertical Scanning).当整个屏幕刷新完毕 ...
- iOS 保持界面流畅的技巧 (转载)
这篇文章会非常详细的分析 iOS 界面构建中的各种性能问题以及对应的解决思路,同时给出一个开源的微博列表实现,通过实际的代码展示如何构建流畅的交互. Index 演示项目 屏幕显示图像的原理 卡顿产生 ...
- 如何让iOS 保持界面流畅?这些技巧你知道吗
如何让iOS 保持界面流畅?这些技巧你知道吗 作者:ibireme这篇文章会非常详细的分析 iOS 界面构建中的各种性能问题以及对应的解决思路,同时给出一个开源的微博列表实现,通过实际的代码展示如 ...
随机推荐
- Ansible 安装使用过程中遇到过的问题
1.[root@ansible ~]# ansible-doc -l [DEPRECATION WARNING]: docker is kept for backwards compatibility ...
- NOIP2017普及组初赛总结
去年,我普及组复赛翻车,居然没进一等奖,于是,今年,我只能再做一次普及组. 这次初赛我93.5分,居然是中山市第一--(中山市太弱了?) 其实我觉得我没考好. 比赛时第二题(计算机存储数据的基本单位是 ...
- windows下bat批量处理启动exe
新建文本文档,start.dat start "" "D:\QQ\anzhaung\Bin\QQ.exe" 启动QQ cd ./当前文件夹下,../上一文件夹下 ...
- Django项目:CMDB(服务器硬件资产自动采集系统)--05--05CMDB采集硬件数据的插件
#__init__.py # ————————05CMDB采集硬件数据的插件———————— from config import settings import importlib # —————— ...
- SQL Server数据库存储过程的异常处理
SQL Server数据库存储过程的异常处理是非常重要的,明确的异常提示能够帮助我们快速地找到问题的根源,节省很多时间.本文我们就以一个插入数据为例来说明SQL Server中的存储过程怎么捕获异常的 ...
- SQL2005自动备份,定期删除的维护计划及自动定期清除日志
作为一名DBA,他们最常见的日常任务是: 1)定期完成数据库的完全备份或差异备份.2)定期清理备份文件,因为存储空间有限,可能只需要保存一个时期段内的文件(比如一周内或一月内). 而如何做到这两点呢? ...
- Shell 语法之信号与作业
Linux 使用信号与系统上运行的进程进行通信. Linux 编程中最常见的 Linux 系统信号 信号 值 描述 1 SIGHUP 挂起进程 2 SIGINT 中断进程 3 SIGQU ...
- Promise的源码实现(符合Promise/A+规范)
我们手写一个Promise/A+规范,然后安装测试脚本,以求通过这个规范. //Promise/A+源代码 // new Promise时,需要传递一个executor执行器,执行器立即执行 // e ...
- 跟我一起做一个vue的小项目(二)
这个vue项目是紧跟着之前的项目跟我一起做一个vue的小项目(一)来的. 我继续后面的开发(写的比较粗糙,边学边记录) 下图是header头部的样式 header组件内容如下 //header.vue ...
- openCV图像合成
#include <iostream> #include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.h ...