sunwengang blog

developer | android display/graphics

  1. 1. vsync相关线程
    1. 1.1. 四种vsync
    2. 1.2. 硬件vsync
    3. 1.3. 函数调用总流程图
    4. 1.4. SF创建EventThread(app&sf)
    5. 1.5. SF注册Connection
  2. 2. sf请求vsync
    1. 2.1. EventThread线程唤醒函数threadmain
    2. 2.2. BitTube
    3. 2.3. DisplayEventReceiver
    4. 2.4. DispSyncSource.setVSyncEnabled开启硬件Vsync
  3. 3. 硬件VSYNC从HWComposer HAL发到EventThread
    1. 3.1. mPeriod Vsync周期时长值变更流程
    2. 3.2. 流程图及部分代码
    3. 3.3. resyncToHardwareVsync打开硬件VYSNC
    4. 3.4. *addResyncSample更新mPeriod
      1. 3.4.1. 重要变量的含义:
      2. 3.4.2. Code
      3. 3.4.3. 计算的相移图
    5. 3.5. setVsyncEnabled硬件VSYNC开关控制
  4. 4. DispSync
    1. 4.1. DispSync初始化
    2. 4.2. addEventListener唤醒线程DispSyncThread
    3. 4.3. HWComposer回调onVysncReceived
  5. 5. 计算SW vsync并向APP/SF发送vsync信号
    1. 5.1. 计算SW Vsync下一个vsync时间
    2. 5.2. 向SF/APP EventThread发送vsync信号
  6. 6. postComposition更新SW Vsync的误差值
    1. 6.1. addPresentFence
  7. 7. 参考文献

为了理解systrace中HW Vsync, sf vsync, app vsync的含义和作用。这里主要参照Android R AOSP源码对这几种VSYNC的关系和调用流程进行大致的梳理。

vsync相关线程

  • EventControlThread: 控制硬件vsync的开关
  • DispSyncThread: 软件产生vsync的线程,接收HWComposer HAL的VSYNC信号,并分发给EventThread
  • SF EventThread: 该线程用于SurfaceFlinger接收vsync信号用于渲染
  • App EventThread: 该线程用于接收vsync信号并且上报给App进程,App开始绘制

四种vsync

从这4个线程,可以将vsync分为4种不同的类型:

  1. HW vsync, 真实由硬件产生的vsync信号
  2. SW vsync, 由DispSync产生的vsync信号
  3. SF vsync, SF接收到的vsync信号
  4. App vsync, App接收到的vsync信号

4个vsync信号之间的关系

硬件vsync

HWComposer HAL通过callback函数,把VSYNC信号传给DispSyncThread,DispSyncThread传给EventThread

vysnc相关线程

函数调用总流程图

完整流程图

部分流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
SurfaceFlinger::init() ---->
SurfaceFlinger::processDisplayHotplugEventsLocked() ---->
SurfaceFlinger::initScheduler 创建sf thread和app thread ---->
(1)Scheduler::createConnection ---->
Scheduler::createConnectionInternal ---->
EventThread::createEventConnection [new EventThreadConnection创建对象]

(2)MessageQueue::setEventConnection ---->
(2.1) mEventTube.getFd()
(2.2) stealReceiveChannel
(2.3) MessageQueue::cb_eventReceiver ---->
MessageQueue::eventReceiver [接收Vsync信号] ---->
MessageQueue::Handler::dispatchInvalidate [Handler消息处理]---->
MessageQueue::Handler::handleMessage ---->
SurfaceFlinger::onMessageReceived ---->
SurfaceFlinger::onMessageInvalidate ----->

//合成刷新是通过frameAvailableListener->onFrameAvailable(item)触发
SurfaceFlinger::signalLayerUpdate() 请求合成 ---->
MessageQueue::invalidate() ----->
EventThreadConnection::requestNextVsync()

SF创建EventThread(app&sf)

1
2
3
4
5
6
7
8
9
10
11
12
13
//函数SurfaceFlinger::initScheduler
// start the EventThread,调用setVsyncEnabled函数控制硬件Vysnc
mScheduler =
getFactory().createScheduler([this](bool enabled) { setVsyncEnabled(enabled); },
*mRefreshRateConfigs, *this);
mAppConnectionHandle =
mScheduler->createConnection("app", mPhaseConfiguration->getCurrentOffsets().late.app,
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
mScheduler->createConnection("sf", mPhaseConfiguration->getCurrentOffsets().late.sf,
[this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
});

SF注册Connection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp
EventThreadConnection::EventThreadConnection(EventThread* eventThread,
ResyncCallback resyncCallback,
ISurfaceComposer::ConfigChanged configChanged)
: resyncCallback(std::move(resyncCallback)),
mConfigChanged(configChanged),
mEventThread(eventThread),
mChannel(gui::BitTube(8 * 1024 /* default size is 4KB, double it */)) {}

void EventThreadConnection::onFirstRef() {
// NOTE: mEventThread doesn't hold a strong reference on us
mEventThread->registerDisplayEventConnection(this);
}

status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
std::lock_guard<std::mutex> lock(mMutex);

// this should never happen
auto it = std::find(mDisplayEventConnections.cbegin(),
mDisplayEventConnections.cend(), connection);
if (it != mDisplayEventConnections.cend()) {
ALOGW("DisplayEventConnection %p already exists", connection.get());
mCondition.notify_all();
return ALREADY_EXISTS;
}
//添加到mDisplayEventConnections集合中
mDisplayEventConnections.push_back(connection);
//唤醒threadMain函数(唤醒所有等待队列中阻塞的线程,存在锁争用,只有一个线程能够获得锁)
mCondition.notify_all();
return NO_ERROR;
}

Note: 有关notify_allunique_lock<std::mutex>锁可参考:C++11条件变量:notify_one()与notify_all()的区别


sf请求vsync

两条请求vsync的流程:

  1. 参考signalLayerUpdate通知Layer更新信息开始,SF触发合成开始请求VSYNC

  2. 当显示屏准备完毕,SF EventThread connection开始监听Vsync信号,相关流程:

1
2
3
4
5
6
7
8
SurfaceFlinger::init()   ---->
SurfaceFlinger::initializeDisplays() 设置初始条件 ----->
SurfaceFlinger::onInitializeDisplays() ----->
SurfaceFlinger::setTransactionState ---->
SurfaceFlinger::setTransactionFlags ---->
SurfaceFlinger::signalTransaction() ---->
MessageQueue::invalidate() [在请求刷新合成时也会调用] ----->
EventThread::requestNextVsync

EventThread线程唤醒函数threadmain

部分代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
//frameworks/native/services/surfaceflinger/Scheduler/EventThread.cpp
void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
if (connection->resyncCallback) {
connection->resyncCallback();
}

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

if (connection->vsyncRequest == VSyncRequest::None) { //None=-1
connection->vsyncRequest = VSyncRequest::Single; //Single=0,只接收一次信号
mCondition.notify_all(); //唤醒threadmain函数
}
}
  1. 在threadmain函数其中创建了DisplayEventReceiver对象,该类用于传输VSYNC信号。
1
2
3
4
5
6
7
8
DisplayEventReceiver::DisplayEventReceiver  (MessageQueue::setEventConnection) ---->
EventThreadConnection::stealReceiveChannel ----->

//函数MessageQueue::setEventConnection也会调用到此处
status_t EventThreadConnection::stealReceiveChannel(gui::BitTube* outChannel) {
outChannel->setReceiveFd(mChannel.moveReceiveFd());
return NO_ERROR;
}
  1. 调用DispSyncSource.setVSyncEnabled开启硬件Vsync

BitTube

参考:setEventThread变更

BitTube,其实现是socketpairt套接字,用于传递消息。Buffer大小是4K

DisplayEventReceiver

查看该类的头文件,关于vsync的主要函数作用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//frameworks/native/libs/gui/include/gui/DisplayEventReceiver.h

public:
//DisplayEventReceiver创建并注册了SF的一个事件连接,默认禁止VSync
//通过调用setVSyncRate、requestNextVsync开始接受。其他事件则即刻分发
explicit DisplayEventReceiver(
ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp,
ISurfaceComposer::ConfigChanged configChanged =
ISurfaceComposer::eConfigChangedSuppress);

//获取用于接收事件的文件描述符,该描述符由本类持有,不得关闭
int getFd() const;

//从队列中读取事件并返回事件个数如果返回NOT_ENOUGH_DATA
//如果返回的数据不够多,则对象将永远无效,应该销毁,并且不应该再次调用getEvents
ssize_t getEvents(Event* events, size_t count);
static ssize_t getEvents(gui::BitTube* dataChannel, Event* events, size_t count);

//向队列中写入事件并返回写入的数量
static ssize_t sendEvents(gui::BitTube* dataChannel, Event const* events, size_t count);

//设置VSync分发频率,每次VSync事件返回1,其他事件返回2,没有事件返回0
status_t setVsyncRate(uint32_t count);

//请求下一次Vsync
status_t requestNextVsync();

//强制请求当前primary display的config属性
status_t requestLatestConfig();
private:
sp<IDisplayEventConnection> mEventConnection;
std::unique_ptr<gui::BitTube> mDataChannel;
};

DispSyncSource.setVSyncEnabled开启硬件Vsync

流程:

1
2
3
4
EventThread::threadMain   ----->
DispSyncSource::setVSyncEnabled ---->
surfaceflinger/Scheduler/DispSync.cpp -- DispSync::addEventListener ---->
class DispSyncThread : public Thread -- addEventListener
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//surfaceflinger/Scheduler/EventThread.cpp
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
.....
State nextState;
if (mVSyncState && vsyncRequested) {
nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
} else {
ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected");
nextState = State::Idle;
}

if (mState != nextState) {
if (mState == State::VSync) {
mVSyncSource->setVSyncEnabled(false);
} else if (nextState == State::VSync) {
mVSyncSource->setVSyncEnabled(true);
}

mState = nextState;
}
....
}

//surfaceflinger/Scheduler/DispSyncSource.cpp
void DispSyncSource::setVSyncEnabled(bool enable) {
std::lock_guard lock(mVsyncMutex);
if (enable) {
//开启硬件Vsync信号就是添加EventListener
status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
static_cast<DispSync::Callback*>(this),
mLastCallbackTime);
} else {
status_t err = mDispSync->removeEventListener(static_cast<DispSync::Callback*>(this),
&mLastCallbackTime);
if (mDolphinCheck) {
if (mDolphinCheck(mName)) {
status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
static_cast<DispSync::Callback*>(this),
mLastCallbackTime);
if (err != NO_ERROR) {
ALOGE("error registering vsync callback: %s (%d)", strerror(-err), err);
}
}
}
}
mEnabled = enable;
}

硬件VSYNC从HWComposer HAL发到EventThread

SF请求合成时关于Vsync的部分流程:

1
2
3
4
5
6
7
8
SurfaceFlinger::onMessageInvalidate  ---->
SurfaceFlinger::updateFrameScheduler() ----->
(1) SurfaceFlinger::getVsyncPeriod() ---->
surfaceflinger/DisplayHardware/HWC2.cpp -- Display::getDisplayVsyncPeriod

(2) Scheduler::resyncToHardwareVsync
(3) DispSync::addResyncSample ----->
DispSync::updateModelLocked [开始计算更新SW vsync 模型]

mPeriod Vsync周期时长值变更流程

流程:

1
2
3
4
5
6
7
8
9
10
11
12
SurfaceFlinger::init()   ---->
SurfaceFlinger::initializeDisplays() 设置初始条件 ----->
SurfaceFlinger::onInitializeDisplays() ----->
SurfaceFlinger::setPowerModeInternal 设置Display的power mode ----->
(1) Scheduler::onScreenAcquired

(2) Scheduler::resyncToHardwareVsync 通过硬件Vsync重新设置软件vysnc ----->
Scheduler::setVsyncPeriod 设置vsync周期时长 ----->

(1) DispSync::setPeriod
(2) DispSync::beginResync()
(3) EventControlThread::setVsyncEnabled 唤醒threadmain线程[如果硬件vsync没有enable,那么就通知EventControlThread去通知硬件enable VSYNC]

流程图及部分代码

硬件VSYNC从HWComposer HAL发到EventThread

resyncToHardwareVsync打开硬件VYSNC

SurfaceFlinger在初始化HWComposer时会默认关闭硬件Vsync信号,这里直接调用eventControl

而resyncToHardwareVsync则是和硬件VSYNC进行同步,通过调用到setVsyncEnabled开启硬件VSYNC

surfaceflinger/Scheduler/Scheduler.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period, bool force_resync) {
{
std::lock_guard<std::mutex> lock(mHWVsyncLock);
//表示硬件VSYNC被enable
if (makeAvailable) {
mHWVsyncAvailable = makeAvailable;
} else if (!mHWVsyncAvailable) {
// Hardware vsync is not currently available, so abort the resync
// attempt for now
return;
}
}
if (period <= 0) {
return;
}
setVsyncPeriod(period, force_resync);
}

void Scheduler::setVsyncPeriod(nsecs_t period, bool force_resync) {
std::lock_guard<std::mutex> lock(mHWVsyncLock);
//设置DispSync模型里period为显示设备的频率
mPrimaryDispSync->setPeriod(period);

if (!mPrimaryHWVsyncEnabled || force_resync) {
mPrimaryDispSync->beginResync();
//如果硬件vsync没有enable,那么就通知EventControlThread去通知硬件enable VSYNC,这个和DispSync的setVsyncEnabled是不一样的
mEventControlThread->setVsyncEnabled(true);
mPrimaryHWVsyncEnabled = true;
}
}

setVsyncEnabled会释放mCond信号,这样在EventControlThread的threadLoop里的mCond会被唤醒去操作硬件Vsync开关

*addResyncSample更新mPeriod

重要变量的含义:

  • 硬件vsync样本个数:MIN_RESYNC_SAMPLES_FOR_UPDATE(要6个硬件vsync样本以上才计算,当然样本越多,模型越精确)
  • mPeriod:即是显示屏的刷新率,这里mPeriod是根据样本个数去掉一个最大一个最小,算平均
  • mPhase:偏移时间,这个相称和具体的SF/APP Thread里固定的相称是不一样的,这个相移是针对 mPeroid的一个偏移
  • mModelUpdated:表示是否模型已经更新
  • mReferenceTime:第一个硬件Vsync的时间,每次SW vsync计算下一个vsync时间时,都是以该时间作为基准,这样可以减少误差

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//surfaceflinger/Scheduler/DispSync.cpp
void DispSync::beginResync() {
Mutex::Autolock lock(mMutex);
ALOGV("[%s] beginResync", mName);
resetLocked();
}

bool DispSync::addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> /*hwcVsyncPeriod*/,
bool* periodFlushed) {
Mutex::Autolock lock(mMutex);

ALOGV("[%s] addResyncSample(%" PRId64 ")", mName, ns2us(timestamp));

*periodFlushed = false;
//MAX_RESYNC_SAMPLES=32,即最大只保存32次硬件vysnc时间戳,用于计算SW Vsync模型
//mNumResyncSamples表示已有硬件Vysnc样本个数
//mFirstResyncSample用于记录第几个硬件vysnc
const size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;
//mResyncSamples用于记录每个硬件vsync样本的时间戳
mResyncSamples[idx] = timestamp;
if (mNumResyncSamples == 0) {
mPhase = 0;
ALOGV("[%s] First resync sample: mPeriod = %" PRId64 ", mPhase = 0, "
"mReferenceTime = %" PRId64,
mName, ns2us(mPeriod), ns2us(timestamp));
} else if (mPendingPeriod > 0) {
....
if (mTraceDetailedInfo) {
ATRACE_INT("DispSync:PendingPeriod", mPendingPeriod);
ATRACE_INT("DispSync:IntendedPeriod", mIntendedPeriod);
}
*periodFlushed = true;
}
}
.....
// Always update the reference time with the most recent timestamp.
mReferenceTime = timestamp;
mThread->updateModel(mPeriod, mPhase, mReferenceTime);

if (mNumResyncSamples < MAX_RESYNC_SAMPLES) {
mNumResyncSamples++;
} else {
mFirstResyncSample = (mFirstResyncSample + 1) % MAX_RESYNC_SAMPLES;
}
//开始计算更新SW Vsync模型
updateModelLocked();
......
ALOGV("[%s] addResyncSample returning %s", mName, modelLocked ? "locked" : "unlocked");
if (modelLocked) {
*periodFlushed = true;
mThread->lockModel();
}
return !modelLocked;
}

//计算更新SW Vsync模型,更新完后就会关闭硬件VSYNC信号
void DispSync::updateModelLocked() {
//MIN_RESYNC_SAMPLES_FOR_UPDATE=6
// 如果已经保存了6个以上的 硬件 vsync样本后,就要开始计算 sw vsync模型了
if (mNumResyncSamples >= MIN_RESYNC_SAMPLES_FOR_UPDATE) {
nsecs_t durationSum = 0;
nsecs_t minDuration = INT64_MAX;
nsecs_t maxDuration = 0;
static constexpr size_t numSamplesSkipped = 2; //跳过两个,因为可能存在不准确、延迟
//还记得上面 如果 mNumResyncSamples=0,即第一个硬件vsync时,直接更新SW vsync模型了,所以这里把第一个给去除掉
for (size_t i = numSamplesSkipped; i < mNumResyncSamples; i++) {
size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
size_t prev = (idx + MAX_RESYNC_SAMPLES - 1) % MAX_RESYNC_SAMPLES;

// mResyncSamples[idx] - mResyncSamples[prev] 这个差值就是计算出两个硬件vsync样本之间的时间间隔
nsecs_t duration = mResyncSamples[idx] - mResyncSamples[prev];
// durationSum 表示保存的所有样本(除去前两个vsync)时间间隔之后,用于后面计算 平均 mPeriod
durationSum += duration;
minDuration = min(minDuration, duration);
maxDuration = max(maxDuration, duration);
}

// 去掉一个最小,一个最大值再来计算平均值,这个平均值就是硬件vsync产生的时间间隔
durationSum -= minDuration + maxDuration;
// 减去4
mPeriod = durationSum / (mNumResyncSamples - numSamplesSkipped - 2);

//下面计算出模型需要的偏移, 因为现在 mPeriod 算出来的是平均值,所以并不是真的硬件vsync时间间隔就是 mPeriod, 存在着偏移与噪音(这个和样本个数有很大的关系)
// 即有些样本信号的时间间隔大于平均值,而有些样本时间间隔小于平均值,而这些与 mPriod的差值就是偏移
// 下面就是要算出这些平均的偏移值
double sampleAvgX = 0;
double sampleAvgY = 0;
//将硬件vsync的时间间隔换算成对应的度数,即刻度,这里的刻度表示每ns代表多少度
// M_PI是圆周率 3.14159265359f,其中2π就是值360度
double scale = 2.0 * M_PI / double(mPeriod);

for (size_t i = numSamplesSkipped; i < mNumResyncSamples; i++) {
size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
nsecs_t sample = mResyncSamples[idx] - mReferenceTime;
// 这里对mPeriod取余就是相对于mPeriod倍数的偏移值,然后将其转换成对应的度数
double samplePhase = double(sample % mPeriod) * scale;
sampleAvgX += cos(samplePhase); //依次累加成 sampleAvgX
sampleAvgY += sin(samplePhase); //依次累加成 sampleAvgY
}

//获得在x轴与y轴的偏移的平均值
sampleAvgX /= double(mNumResyncSamples - numSamplesSkipped);
sampleAvgY /= double(mNumResyncSamples - numSamplesSkipped);

//最后再通过atan2获得最终的相移值
mPhase = nsecs_t(atan2(sampleAvgY, sampleAvgX) / scale);

//如果相移偏过了mPeriod的一半,那么重新调整一下
if (mPhase < -(mPeriod / 2)) {
mPhase += mPeriod;
ALOGV("[%s] Adjusting mPhase -> %" PRId64, mName, ns2us(mPhase));
}
// 将最新的 偏移 mPhase和 vsync时间间隔mPeriod和mReferenceTime更新到SW vsync模型当中
mThread->updateModel(mPeriod, mPhase, mReferenceTime);

// 模型更新了
mModelUpdated = true;
}
}

计算的相移图

计算模型的相移图图示

setVsyncEnabled硬件VSYNC开关控制

1
2
3
4
5
SurfaceFlinger::init() ---->
SurfaceFlinger::processDisplayHotplugEventsLocked() ---->
SurfaceFlinger::initScheduler 创建sf thread和app thread ---->
SurfaceFlinger::setVsyncEnabled(bool enabled) [传入true,开启硬件vsync] ----->
SurfaceFlinger::setVsyncEnabledInternal(bool enabled)

硬件vsync相关函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void SurfaceFlinger::setVsyncEnabledInternal(bool enabled) {
ATRACE_CALL();
Mutex::Autolock lockVsync(mVsyncLock);
//复制
mHWCVsyncPendingState = enabled ? hal::Vsync::ENABLE : hal::Vsync::DISABLE;

auto displayId = getInternalDisplayIdLocked();
if (mNextVsyncSource) {
// Disable current vsync source before enabling the next source
if (mActiveVsyncSource) {
displayId = mActiveVsyncSource->getId();
getHwComposer().setVsyncEnabled(*displayId, hal::Vsync::DISABLE);
}
displayId = mNextVsyncSource->getId();
} else if (mActiveVsyncSource) {
displayId = mActiveVsyncSource->getId();
}
getHwComposer().setVsyncEnabled(*displayId, mHWCVsyncPendingState);
if (mNextVsyncSource) {
mActiveVsyncSource = mNextVsyncSource;
mNextVsyncSource = NULL;
}
}

DispSync

DispSyncThread是软件产生vsync的线程,也控制硬件VSync信号同步。DispSync是定义在SurfaceFlinger类里的成员变量,因此在初始化 SurfaceFlinger时,就会初始化DispSync。

DispSync初始化

流程:

1
2
3
4
5
6
SurfaceFlinger::init() ---->
SurfaceFlinger::processDisplayHotplugEventsLocked() --->
SurfaceFlinger::initScheduler ----->
surfaceflinger/SurfaceFlingerDefaultFactory.cpp -- DefaultFactory::createScheduler --->
Scheduler::Scheduler [构造函数] ---->
std::unique_ptr<DispSync> createDispSync [创建DispSync]

代码:

Scheduler构造函数:

frameworks/native/services/surfaceflinger/Scheduler/Scheduler.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
const scheduler::RefreshRateConfigs& refreshRateConfig,
ISchedulerCallback& schedulerCallback, bool useContentDetectionV2,
bool useContentDetection)
: mSupportKernelTimer(sysprop::support_kernel_idle_timer(false)),
mPrimaryDispSync(createDispSync(mSupportKernelTimer)), //调用createDispSync函数
mEventControlThread(new impl::EventControlThread(std::move(function))),
mSchedulerCallback(schedulerCallback),
mRefreshRateConfigs(refreshRateConfig),
mUseContentDetection(useContentDetection),
mUseContentDetectionV2(useContentDetectionV2) { ....

std::unique_ptr<DispSync> createDispSync(bool supportKernelTimer) {
...
} else {
return std::make_unique<impl::DispSync>("SchedulerDispSync",
sysprop::running_without_sync_framework(true));
}
}
surfaceflinger/Scheduler/DispSync.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//构造函数
DispSync::DispSync(const char* name, bool hasSyncFramework)
: mName(name), mIgnorePresentFences(!hasSyncFramework) {
mThread = new DispSyncThread(name, mTraceDetailedInfo); //创建DispSyncThread对象
mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); //线程执行
...
}

class DispSyncThread : public Thread {
public:
DispSyncThread(const char* name, bool showTraceDetailedInfo)
: mName(name),
mStop(false),
mModelLocked("DispSync:ModelLocked", false),
mPeriod(0), //初始化为0
mPhase(0),
mReferenceTime(0),
mWakeupLatency(0),
mFrameNumber(0),
mTraceDetailedInfo(showTraceDetailedInfo) {}
......

virtual bool threadLoop() {
status_t err;
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
...
//当threadLoop第一次进来后,由于mPeriod初始化为0,所以一直死等在这里
if (mPeriod == 0) {
err = mCond.wait(mMutex);
if (err != NO_ERROR) {
ALOGE("error waiting for new events: %s (%d)", strerror(-err), err);
return false;
}
continue;
}
//计算下一次vsync事件的时间
targetTime = computeNextEventTimeLocked(now);
.....
}

addEventListener唤醒线程DispSyncThread

接着上面threadmain函数流程调用到addEventListener,此处将唤醒上面threadloop的mCond.wait(mMutex)

1
2
3
4
5
6
7
8
9
status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback,
nsecs_t lastCallbackTime) {
...
mEventListeners.push_back(listener);
//唤醒线程,threadLoop可以跳出循环继续执行
mCond.signal();

return NO_ERROR;
}

mPeriod == 0)则仍旧是0,所以此时会continue继续往下执行。计算下一个Vsync信号的时间戳,并且上报给EventListener,如此DispSyncThread模型就会运作起来。


HWComposer回调onVysncReceived

1
2
3
4
surfaceflinger/DisplayHardware/HWComposer.cpp  -- class ComposerCallbackBridge - android::hardware::Return<void> onVsync  ---->
SurfaceFlinger::onVsyncReceived ---->
(1) addResyncSample 更新vysnc计算模型
(2) VSyncModulator::onRefreshRateChangeCompleted

此处会调用到addResyncSample函数,该函数会加入硬件vsync的样本,目的是为了计算、更新SW VSYNC的参数。具体解释将对应小节。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId,
int64_t timestamp,
std::optional<hal::VsyncPeriodNanos> vsyncPeriod) {
ATRACE_NAME("SF onVsync"); //systrace

Mutex::Autolock lock(mStateLock);
// Ignore any vsyncs from a previous hardware composer.
if (sequenceId != getBE().mComposerSequenceId) {
return;
}

if (!getHwComposer().onVsync(hwcDisplayId, timestamp)) {
return;
}

bool periodFlushed = false;
mScheduler->addResyncSample(timestamp, vsyncPeriod, &periodFlushed);
if (periodFlushed) {
mVSyncModulator->onRefreshRateChangeCompleted();
}
}

//surfaceflinger/Scheduler/VSyncModulator.cpp
void VSyncModulator::onRefreshRateChangeCompleted() {
if (!mRefreshRateChangePending) {
return;
}
mRefreshRateChangePending = false;
updateOffsets();
}

void VSyncModulator::updateOffsets() {
std::lock_guard<std::mutex> lock(mMutex);
updateOffsetsLocked();
}

void VSyncModulator::updateOffsetsLocked() {
const Offsets& offsets = getNextOffsets();

mPhaseOffsetControl.setPhaseOffset(mSfConnectionHandle, offsets.sf);
mPhaseOffsetControl.setPhaseOffset(mAppConnectionHandle, offsets.app);

mOffsets = offsets;

if (!mTraceDetailedInfo) {
return;
}

const bool isEarly = &offsets == &mOffsetsConfig.early;
const bool isEarlyGl = &offsets == &mOffsetsConfig.earlyGl;
const bool isLate = &offsets == &mOffsetsConfig.late;

ATRACE_INT("Vsync-EarlyOffsetsOn", isEarly);
ATRACE_INT("Vsync-EarlyGLOffsetsOn", isEarlyGl);
ATRACE_INT("Vsync-LateOffsetsOn", isLate);
}

计算SW vsync并向APP/SF发送vsync信号

在计算完后,继续执行DispSyncThread的threadloop函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//surfaceflinger/Scheduler/DispSync.cpp
virtual bool threadLoop() {
status_t err;
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
...
//计算下一次vsync事件的时间
targetTime = computeNextEventTimeLocked(now);

bool isWakeup = false;
//等待计算出来的下一次vsync时间到来
//如果到了就发送SW VSYNC信号
if (now < targetTime) {
if (mTraceDetailedInfo) ATRACE_NAME("DispSync waiting");

if (targetTime == INT64_MAX) {
ALOGV("[%s] Waiting forever", mName);
err = mCond.wait(mMutex);
} else {
ALOGV("[%s] Waiting until %" PRId64, mName, ns2us(targetTime));
//等到SW VSYNC时间到了,就唤醒,发送vsync信号
err = mCond.waitRelative(mMutex, targetTime - now);
}

if (err == TIMED_OUT) {
isWakeup = true;
} else if (err != NO_ERROR) {
ALOGE("error waiting for next event: %s (%d)", strerror(-err), err);
return false;
}
}

now = systemTime(SYSTEM_TIME_MONOTONIC);

//计算wake up时间, 但是不能超过1.5 ms
static const nsecs_t kMaxWakeupLatency = us2ns(1500);

if (isWakeup) {
//累加mWakeupLatency醒来的时间
//用于在后面计算SW VSYNC时间
//所有的wake up时间最大不能超过1.5 ms
mWakeupLatency = ((mWakeupLatency * 63) + (now - targetTime)) / 64;
mWakeupLatency = min(mWakeupLatency, kMaxWakeupLatency);
if (mTraceDetailedInfo) {
ATRACE_INT64("DispSync:WakeupLat", now - targetTime);
ATRACE_INT64("DispSync:AvgWakeupLat", mWakeupLatency);
}
}
//收回回调的EventListener(在前面addEventListener中)
//
callbackInvocations =
gatherCallbackInvocationsLocked(now, computeNextRefreshLocked(0, now));
}

if (callbackInvocations.size() > 0) {
//向SF/APP EventThread发送vsync信号
fireCallbackInvocations(callbackInvocations);
}
}

return false;
}

计算SW Vsync下一个vsync时间

这里其实就最多只有两种EventListener, 一个是SF EventThread,一个是App EventThread。

它们都需要接收Vsync信号来分别做不同的事情。

但是实际上两个线程都有一个vsync phase offset偏移值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
//surfaceflinger/Scheduler/DispSync.cpp
private:
nsecs_t computeNextEventTimeLocked(nsecs_t now) {
if (mTraceDetailedInfo) ATRACE_CALL();
ALOGV("[%s] computeNextEventTimeLocked", mName);
nsecs_t nextEventTime = INT64_MAX;
for (size_t i = 0; i < mEventListeners.size(); i++) {
//对所有的EventListener进行分别计算,里面的mLastEventTime值不同
nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i], now);
if (t < nextEventTime) {
nextEventTime = t;
}
}
return nextEventTime;
}

nsecs_t computeListenerNextEventTimeLocked(const EventListener& listener, nsecs_t baseTime) {
if (mTraceDetailedInfo) ATRACE_CALL();
//计算的是上一次vsync事件的时间,等于上一次vsync事件 + wake up唤醒时间
nsecs_t lastEventTime = listener.mLastEventTime + mWakeupLatency;
//一般情况是fasle;
//如果是true,比如第一次,threadLoop的now生成的时间比较早,而addEventListener发生的比较晚,
//listener的lastEventTime设为了当前的系统时间,此时baseTime就会小于lastEventTime
if (baseTime < lastEventTime) {
//重新修正baseTime
baseTime = lastEventTime;
ALOGV("[%s] Clamping baseTime to lastEventTime -> %" PRId64, mName, ns2us(baseTime));
}
//减去参考时间(第一个硬件vsync样本的时间)
baseTime -= mReferenceTime;
//mPhase是通过硬件vsync样本计算出来的
//listener.mPhase是固定的具体在编译时设置的(在PhaseOffsets.cpp中)
nsecs_t phase = mPhase + listener.mPhase;
//减去偏移
baseTime -= phase;

if (baseTime < 0) {
ALOGV("[%s] Correcting negative baseTime", mName);
baseTime = -mPeriod;
}
//求出下一时刻发送sw vsync的时间,这个时间是以第一个硬件vsync作为参考来这样计算
//如果以一个sw vsync时间作为参考,因为sw vsync的时间本身就是一种根据模型模拟出来的,所以本身存在误差,
//所以如果每个sw vsync以上一个作为base的话,那么它的误差会慢慢积累;
//而每次以第一个硬件vsync时间作为基准,那么每个sw vsync的误差,并不会累加,这样就相对来说更加精确些
nsecs_t numPeriods = baseTime / mPeriod;
//计算距离第一个硬件Vsync时间的偏移,即得到下一个sw vsync的时间,numPeriods + 1,注意是下一个vsync的时间
nsecs_t t = (numPeriods + 1) * mPeriod + phase;
//t是相对于每一个硬件vsync的时间
t += mReferenceTime;

//如果这个vsync距离上一个vsync时间小于3/5个mPeriod的话,为了避免连续的两个sw vsync,
//那么这次sw vsync就放弃了,直接放到下一个周期里
if (isCloseToPeriod(t - listener.mLastEventTime)) {
t += mPeriod;
ALOGV("[%s] Modifying t -> %" PRId64, mName, ns2us(t));
}
//当然算出来的时间要减去wake up的时间了,这样才能精确的模拟硬件vsync的时间,
//注意mWakeupLatency是所有wake up的时间累加,但是最大只能到1.5ms
t -= mWakeupLatency;
ALOGV("[%s] Corrected for wakeup latency -> %" PRId64, mName, ns2us(t));

return t;
}

bool isCloseToPeriod(nsecs_t duration) {
// Ratio of 3/5 is arbitrary, but it must be greater than 1/2.
return duration < (3 * mPeriod) / 5;
}

向SF/APP EventThread发送vsync信号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//surfaceflinger/Scheduler/DispSync.cpp
std::vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now,
nsecs_t expectedVSyncTime) {
if (mTraceDetailedInfo) ATRACE_CALL();

std::vector<CallbackInvocation> callbackInvocations;
//因为computeListenerNextEventTimeLocked计算的是下一个vsync时间,
//那么这一次的vsync就以上now - mPeriod作为基准时间
nsecs_t onePeriodAgo = now - mPeriod;

for (auto& eventListener : mEventListeners) {
nsecs_t t = computeListenerNextEventTimeLocked(eventListener, onePeriodAgo);

if (t < now) {
if (isCloseToPeriod(now - eventListener.mLastCallbackTime)) {
eventListener.mLastEventTime = t;
ALOGV("[%s] [%s] Skipping event due to model error", mName,
eventListener.mName);
continue;
}

CallbackInvocation ci;
ci.mCallback = eventListener.mCallback;
ci.mEventTime = t;
ci.mExpectedVSyncTime = expectedVSyncTime;
if (eventListener.mPhase < 0) {
ci.mExpectedVSyncTime += mPeriod;
}
ALOGV("[%s] [%s] Preparing to fire, latency: %" PRId64, mName, eventListener.mName,
t - eventListener.mLastEventTime);
//回调
callbackInvocations.push_back(ci);
eventListener.mLastEventTime = t;
eventListener.mLastCallbackTime = now;
}
}
return callbackInvocations;
}

postComposition更新SW Vsync的误差值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::postComposition()
{
ATRACE_CALL();
ALOGV("postComposition");
...
getBE().mDisplayTimeline.updateSignalTimes();
mPreviousPresentFences[1] = mPreviousPresentFences[0];

sp<DisplayDevice> vSyncSource = mNextVsyncSource;
if (mNextVsyncSource == NULL) {
vSyncSource = mActiveVsyncSource;
}
mPreviousPresentFences[0] = vSyncSource ?
getHwComposer().getPresentFence(*vSyncSource->getId()) : Fence::NO_FENCE;
auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFences[0]);
getBE().mDisplayTimeline.push(presentFenceTime);
...
//获取fence
mTransactionCompletedThread.addPresentFence(mPreviousPresentFences[0]);
mTransactionCompletedThread.sendCallbacks();

if (display && display->isPrimary() && display->getPowerMode() == hal::PowerMode::ON &&
presentFenceTime->isValid()) {
mScheduler->addPresentFence(presentFenceTime);
}
...
}

//surfaceflinger/Scheduler/Scheduler.cpp
void Scheduler::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
if (mPrimaryDispSync->addPresentFence(fenceTime)) {
//如果addPresentFence返回true,则说明SW vsync和硬件Vsync的误差太大
//此时就需要重新打开硬件vsync,来重新调节计算SW vsync模型
enableHardwareVsync();
} else {
disableHardwareVsync(false);
}
}

addPresentFence

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//surfaceflinger/Scheduler/DispSync.cpp
bool DispSync::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
Mutex::Autolock lock(mMutex);

if (mIgnorePresentFences) {
return true;
}
//将当前硬件vsync的fence保存到mPresentFences中,
//目的是为了计算偏移
mPresentFences[mPresentSampleOffset] = fenceTime;
mPresentSampleOffset = (mPresentSampleOffset + 1) % NUM_PRESENT_SAMPLES;
//置为0
mNumResyncSamplesSincePresent = 0;
//更新错误信息
updateErrorLocked();
//一般情况下mModelUpdated已经被更新,然后硬件vsync被disable
//所以这里只需要看SW VSYNC的真实的硬件vsync的误差是否在可允许的范围内即可
return !mModelUpdated || mError > kErrorThreshold;
}

上面的mError是方差,当方差大于kErrorThreshold就返回true。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//surfaceflinger/Scheduler/DispSync.cpp
void DispSync::updateErrorLocked() {
if (!mModelUpdated) {
return;
}
int numErrSamples = 0;
nsecs_t sqErrSum = 0;
//NUM_PRESENT_SAMPLES=8
for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {

nsecs_t time = mPresentFences[i]->getCachedSignalTime();
if (time == Fence::SIGNAL_TIME_PENDING || time == Fence::SIGNAL_TIME_INVALID) {
continue;
}
//mReferenceTime是第一个硬件vsync的时间戳(addResyncSample中)
nsecs_t sample = time - mReferenceTime;
//此处sample一般情况下是大于偏移量mPhase的
if (sample <= mPhase) {
continue;
}
5
nsecs_t sampleErr = (sample - mPhase) % mPeriod;
if (sampleErr > mPeriod / 2) {
sampleErr -= mPeriod;
}
//记录偏移差的平方和
sqErrSum += sampleErr * sampleErr;
numErrSamples++;
}
//mError即求出的方差
if (numErrSamples > 0) {
mError = sqErrSum / numErrSamples;
mZeroErrSamplesCount = 0;
} else {
mError = 0;
// Use mod ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT to avoid log spam.
mZeroErrSamplesCount++;
ALOGE_IF((mZeroErrSamplesCount % ACCEPTABLE_ZERO_ERR_SAMPLES_COUNT) == 0,
"No present times for model error.");
}

if (mTraceDetailedInfo) {
ATRACE_INT64("DispSync:Error", mError);
}
}

参考文献

参考google文章: 在 Android 上进行高刷新率渲染

Google官网Multiple Refresh Rate

参考: CCSDN博客 刷新率和Vsync

参考: Android SurfaceFlinger SW Vsync模型

本文作者 : sunwengang
本文使用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议
本文链接 : https://alonealive.github.io/Blog/2021/04/14/2021/210414_android_VsyncStudy/

本文最后更新于 天前,文中所描述的信息可能已发生改变