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 + 1) % 2;
  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(), 0, ALOOPER_EVENT_INPUT, // 监听BitTube的fd,有数据时,调用handler
  this, NULL);
  if (rc < 0) {
    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(), 0, ALOOPER_EVENT_INPUT,
  MessageQueue::cb_eventReceiver, this);
}

在sf进程中直接监听BitTube的fd,当有vsync过来时, 直接由SF的MessageQueue处理

时间: 2024-10-06 22:10:10

vsync信号产生与分发的相关文章

Android SurfaceFlinger服务(六) ----- VSync信号的分发

HWComposer模块产生VSync信号后要经过分发才能送达到关心VSync事件的模块中去.VSync信号分发大致流程为HWComposer->SurfaceFlinger->DispSync->DispSyncSource->各个具体模块.下面具体分析下这个流程. 在上一篇文章中分析到硬件或者软件VSync信号产生时,会回调SurfaceFlinger的onVSyncReceived函数,来看看这个函数: void SurfaceFlinger::onVSyncReceived

关于 视频同步vsync 信号在不同时钟域采样问题

今天调试 视频 4k(3840 x 1920)的vsync信号(时钟为 297Mhz) 进入 170Mhz 的时钟域, 发现输出来的信号信号抖动特别厉害.后来才发现这是不同时钟域 造成的影响. 快 时钟域的信号进入 慢时钟域 可能出现 采集不到的情况.所以我把 一个时钟的高电平 变为 3个时钟的高电平, 这样就能保证 慢时钟域肯定能够采集到. always @(posedge clk or negedge reset_n) begin if (~reset_n) begin rdaddr_req

VSYNC信号传递流向

vsync信号源产生地 1.硬件支持 2.软件模拟 SurfaceFlinger创建的init会初始创建HWComposer void SurfaceFlinger::init() { mHwc = new HWComposer(this,*static_cast<HWComposer::EventHandler *>(this)); } HWComposer::HWComposer( const sp<SurfaceFlinger>& flinger, EventHand

Android 显示系统:Vsync机制

一.Vsync简介: 屏幕的刷新过程是每一行从左到右(行刷新,水平刷新,Horizontal Scanning),从上到下(屏幕刷新,垂直刷新,Vertical Scanning).当整个屏幕刷新完毕,即一个垂直刷新周期完成,会有短暂的空白期,此时发出 VSync 信号.所以,VSync 中的 V 指的是垂直刷新中的垂直-Vertical. Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,VSync是Vertical Synchronization(垂直同步)的缩写,是一种

HSync、VSync与硬件时钟

首先从过去的 CRT 显示器原理说起.CRT 的电子枪按照上面方式,从上到下一行行扫描,扫描完成后显示器就呈现一帧画面,随后电子枪回到初始位置继续下一次扫描.为了把显示器的显示过程和系统的视频控制器进行同步,显示器(或者其他硬件)会用硬件时钟产生一系列的定时信号.当电子枪换到新的一行,准备进行扫描时,显示器会发出一个水平同步信号(horizonal synchronization),简称 HSync:而当一帧画面绘制完成后,电子枪回复到原位,准备画下一帧前,显示器会发出一个垂直同步信号(vert

iOS 保持界面流畅的技巧

这篇文章会非常详细的分析 iOS 界面构建中的各种性能问题以及对应的解决思路,同时给出一个开源的微博列表实现,通过实际的代码展示如何构建流畅的交互. Index演示项目屏幕显示图像的原理卡顿产生的原因和解决方案CPU 资源消耗原因和解决方案GPU 资源消耗原因和解决方案AsyncDisplayKitASDK 的由来ASDK 的资料ASDK 的基本原理ASDK 的图层预合成ASDK 异步并发操作Runloop 任务分发微博 Demo 性能优化技巧预排版预渲染异步绘制全局并发控制更高效的异步图片加载

【凯子哥带你学Framework】Activity界面显示全解析

前几天凯子哥写的Framework层的解析文章<Activity启动过程全解析>,反响还不错,这说明“写让大家都能看懂的Framework解析文章”的思想是基本正确的. 我个人觉得,深入分析的文章必不可少,但是对于更多的Android开发者——即只想做应用层开发,不想了解底层实现细节——来说,“整体上把握,重要环节深入“是更好的学习方式.因为这样既可以有完整的知识体系,又不会在浩瀚的源码世界里迷失兴趣和方向. 所以呢,今天凯子哥又带来一篇文章,接着上一篇的结尾,重点介绍Activity开启之后

Android应用程序UI硬件加速渲染环境初始化过程分析

在Android应用程序中,我们是通过Canvas API来绘制UI元素的.在硬件加速渲染环境中,这些Canvas API调用最终会转化为Open GL API调用(转化过程对应用程序来说是透明的).由于Open GL API调用要求发生在Open GL环境中,因此在每当有新的Activity窗口启动时,系统都会为其初始化好Open GL环境.这篇文章就详细分析这个Open GL环境的初始化过程. 老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注! Open

Android黄油计划之Choreographer原理解析

搞客户端开发,时间也有点了,但是每次想起来,总感觉自己掌握的东西零零散散,没有一点集在的感觉,应用层的懂,framework的也懂,框架啥的了解一点,分层的思想也有一些,JVM的原理啊,内存分配和管理啊,运行机制啊啥的也知道一点,每次下班或者没事了,就在考虑,自己应该有一个主攻方向,往这个方向集中发展一下,首选的几个目标应该是非常清楚的,我们要掌握android,那么关于android的View机制.动画原理这些都是必须要掌握的,所以呢,自己想在这几个方面花些时间,好好研究一下,这样才能使自己更