Vsync流程

Vsync

垂直同步,扫描一帧的同步时间,如屏幕的刷新率为60Hz,那么周期为1/60s,也就是16.66ms一次的时间间隔;

在了解安卓的显示流程的时候,网上一般都会贴个图说是通过VSYNC驱动下的绘制,合成,显示的流程线方式;

1558945552666

实际上由于app和sf都存在着存在一个相位偏移,所以并不是安全按照Vsync的时序来完成这些操作的;

那什么是VSYNC呢?为了有最基本的认识,让我们从底层代码开始讲起,借助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
./drivers/video/fbdev/sunxi/disp2/disp/dev_disp.c
在fb_init的时候,我们就会创建这个内核线程;
fb_init
g_fbi.vsync_task[i] = kthread_create(vsync_thread, (void*)i, task_name);

static int vsync_thread(void *parg)
{
unsigned long disp = (unsigned long)parg;

while (1) {

vsync_proc(disp);
-->snprintf(buf, sizeof(buf), "VSYNC%d=%llu", disp, ts);
envp[0] = buf;
envp[1] = NULL;
kobject_uevent_env(&g_fbi.dev->kobj, KOBJ_CHANGE, envp);
set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (kthread_should_stop())
break;
set_current_state(TASK_RUNNING);
}

return 0;
}
在这个线程里面会不断的上报Vsync的信号,然后休眠;那什么时候唤醒呢?

disp_lcd_enable
disp_sys_register_irq(lcdp->irq_no,0,disp_lcd_event_proc,(void*)lcd,0,0);
disp_lcd_event_proc
sync_event_proc
ret = gdisp.init_para.vsync_event(disp);
vsync_event
drv_disp_vsync_event
wake_up_process(g_fbi.vsync_task[sel]);

根据irq_no和dts可以获知是注册的TCON的中断,也即对应着屏幕的刷新率;

如果我们使用ftrace抓取workqueue的使用情况的话,就能看到有如下的打印

1
2
$ echo workqueue:workqueue_queue_work > /sys/kernel/debug/tracing/set_event
$ cat /sys/kernel/debug/tracing/trace_pipe > out.txt

vsync

对于底层的disp,除了提供VSYNC信号,另外,他还提供了disp_ioctl这套系统调用接口,太多的话就不做阐述,如果后面有哪个接口比较重要再做描述;

HWC

代码目录在hareware/aw/hwc2中

hwc提供了安卓标准的hwc的相关接口实现(hwc2_function_pointer_t);安卓通过HIDL调用到hwc的相关function;然后再通过这些接口实现了对kernel/driver的调用;在hwc中有两个主要的线程,负责监听底层的事件,还有送显;

1558932920872

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
threadResouce/hwc_event_thread.cpp
eventThreadLoop
vsyncUeventParse(context, msg);
callVsync(context, vsync_id, timestamp);
在线程中,如果捕捉到Vsyn的Uevent时间,然后进行回调;

hwc中callback的注册流程:
int32_t hwc_register_callback(hwc2_device_t* device, int32_t descriptor,
hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer)

registerEventCallback(int bitMapDisplay, int32_t descriptor, int zOrder,
hwc2_callback_data_t callback_data, hwc2_function_pointer_t pointer)
registerEventCallback(0x3, descriptor, 0, callbackData, pointer);

surfaceflinge会通过HIDL的方式注册这个回调函数,这个我们后面再讲;

HIDL

那么HIDL怎么玩的?

1558945098496

如上所示就是一个HIDL的玩法;以vsync的callback注册流程为例;

SF_BE:SurfaceFlinger采用的是前后端设计,与HWC相关的逻辑都会放到SurfaceFlingeBE中

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
代码路径:framwwork/nativeservices/surfaceflinger/
SurfaceFlinger.cpp
SurfaceFlinger::init(){
...
mCompositionEngine->setHwComposer(getFactory().createHWComposer(getBE().mHwcServiceName));
mCompositionEngine->getHwComposer().registerCallback(this, getBE().mComposerSequenceId);
...
}

void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
int64_t timestamp) {
ATRACE_NAME("SF onVsync");

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

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

if (hwcDisplayId != getHwComposer().getInternalHwcDisplayId()) {
// For now, we don't do anything with external display vsyncs.
return;
}

bool periodChanged = false;
mScheduler->addResyncSample(timestamp, &periodChanged);
if (periodChanged) {
mVsyncModulator.onRefreshRateChangeDetected();
}
}

HWC2_Client:属于surfaceflinge进程,通过Binder和HWC2的HAL Server交互,命名空间是HWC2

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
代码路径:services/surfaceflinger/DisplayHardware/
HWComposer.cpp
void HWComposer::registerCallback(HWC2::ComposerCallback* callback,
int32_t sequenceId) {
mHwcDevice->registerCallback(callback, sequenceId);
}

std::unique_ptr<HWC2::Device> mHwcDevice;

services/surfaceflinger/DisplayHardware/HWC2.cpp
void Device::registerCallback(ComposerCallback* callback, int32_t sequenceId) {
if (mRegisteredCallback) {
ALOGW("Callback already registered. Ignored extra registration "
"attempt.");
return;
}
mRegisteredCallback = true;
sp<ComposerCallbackBridge> callbackBridge(
new ComposerCallbackBridge(callback, sequenceId));
mComposer->registerCallback(callbackBridge);
}
class ComposerCallbackBridge : public Hwc2::IComposerCallback {
Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override
{
mCallback->onVsyncReceived(mSequenceId, display, timestamp);
return Void();
}
}

services/surfaceflinger/DisplayHardware/ComposerHal.cpp
void Composer::registerCallback(const sp<IComposerCallback>& callback)
{
auto ret = mClient->registerCallback(callback);
if (!ret.isOk()) {
ALOGE("failed to register IComposerCallback");
}
}

HWC SERVER:

client调用到server中标准的接口

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

代码路径:hardware/interfaces/graphics/composer/2.1/

utils/hal/include/composer-hal/2.1/ComposerClient.h
Return<void> registerCallback(const sp<IComposerCallback>& callback) override {
// no locking as we require this function to be called only once
mHalEventCallback = std::make_unique<HalEventCallback>(callback, mResources.get());
mHal->registerEventCallback(mHalEventCallback.get());
return Void();
}

utils/passthrough/include/composer-passthrough/2.1/HwcHal.h
void registerEventCallback(hal::ComposerHal::EventCallback* callback) override {
...
mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this,
reinterpret_cast<hwc2_function_pointer_t>(vsyncHook));
...
}

static void vsyncHook(hwc2_callback_data_t callbackData, hwc2_display_t display,
int64_t timestamp) {
auto hal = static_cast<HwcHalImpl*>(callbackData);
hal->mEventCallback->onVsync(display, timestamp);
}
mDispatch是个结构体
struct {
...
HWC2_PFN_REGISTER_CALLBACK registerCallback;
...
} mDispatch = {};

template <typename T>
bool initDispatch(hwc2_function_descriptor_t desc, T* outPfn) {
auto pfn = mDevice->getFunction(mDevice, desc);
if (pfn) {
*outPfn = reinterpret_cast<T>(pfn);
return true;
} else {
ALOGE("failed to get hwcomposer2 function %d", desc);
return false;
}
}
这里之后我们就可以看到代码是走到各自厂家封装的函数了;

HWC VENDER:

提供hwc2_function_pointer_t的实现;

1
2
3
4
5
6
7
8
9
10
11
12
13
代码路径:hardware/aw/hwc2
hwc.cpp
hwc2_function_pointer_t hwc_device_getFunction(struct hwc2_device* device,
int32_t /*hwc2_function_descriptor_t*/ descriptor)
{
...
case HWC2_FUNCTION_REGISTER_CALLBACK:
return asFP<HWC2_PFN_REGISTER_CALLBACK>(
hwc_register_callback);
}
...

}

总结:

1.安卓提供了一套标准的hwc2_function_pointer_t给厂家去实现,然后自己就可以通过HIDL接口进行调用;

2.在Vsync时间来临时,会通过回调调到SurfaceFlinger的实现函数onVsyncReceived,然后又会通过唤醒DispSync这个线程,通过postEvent传递VSYNC事件,然后MessageQueue收到这个消息后,就会调用对应的hanlder函数,最终调用到SurfaceFlinger中onMessageReceiver处理,这里就会去决策是否要进行合成了;细节后面会讲到,我们现在只需要知道有VSYNC会来的时候会调到SurfaceFlinge的回调就行;

MessageQueue

surfaceflinger启动

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
system/core/rootdir/init.rc
on boot
class_start core

frameworks/native/services/surfaceflinger/surfaceflinger.rc
service surfaceflinger /system/bin/surfaceflinger

./services/surfaceflinger/main_surfaceflinger.cpp
int main(int, char**) {
startGraphicsAllocatorService();
ProcessState::self()->setThreadPoolMaxThreadCount(4);
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();//设定surfaceflinger进程的binder线程池个数上限为4,并启动binder线程池

sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger();
setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);//设置进程优先级
set_sched_policy(0, SP_FOREGROUND);//设置为前台进程

flinger->init(); //初始化
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
sched_setscheduler(0, SCHED_FIFO, &param)//设置进程运行策略

startDisplayService();
flinger->run(); //实行surfaceflinger中的run方法
}

先将创建的线程给打出来,后面有涉及到的线程作用也会提及

1558615784026

MessageQueue创建

类介绍

1
2
3
4
5
6
7
class SurfaceFlinger : public BnSurfaceComposer, 实现SurfaceComposer接口
public PriorityDumper, //实现SurfaceFlinger的信息dump
IBinder::DeathRecipient,
private HWC2::ComposerCallback 实现以下三种事件回调
//onHotplugReceived 屏幕热插拔事件
//onRefreshReceived 当图层的配置参数有变动的时候,SurfaceFlinger前面给的数据不能用的时候
//onVsyncReceived 接受底层硬件上报的垂直同步信息

onFirstRef

1
2
3
4
5
6
7
8
9
10
flinger的数据类型为sp强指针类型,当首次被强指针引用的时候则执行onFirstRef
onFirstRef
mEventQueue->init(this);

services/surfaceflinger/Scheduler/MessageQueue.cpp
void MessageQueue::init(const sp<SurfaceFlinger>& flinger) {
mFlinger = flinger;
mLooper = new Looper(true);
mHandler = new Handler(*this);
}

img

简单介绍一下就是looper不断从MessageQueue中取出一个Message,然后交给其对应的Hanlder;handler通过Looper sendMessgae 到队列中,也负责处理相关的消息,处理的消息为INVALIDATE,REFRESH当Vsync来的时候会调到callback,onVsyncReceived;接下来就是消息的收发是怎么驱动起来的了~

线程创建

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
void SurfaceFlinger::init() {
....
//创建EventControlThread来控制Vsync的开关, DispSyncThread软件产生的Vsync的线程
mScheduler =
getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); },
mRefreshRateConfigs);
--> make_unique<impl::DispSync>("SchedulerDispSync")
-->new DispSyncThread(name, mTraceDetailedInfo);
-->primaryDispSync->init
-->mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
--> mEventControlThread = std::make_unique<impl::EventControlThread>(function);


//获取Vsync周期
auto resyncCallback =
mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));

//SF EventThread该线程用于SurfaceFlinger接受Vsync用于渲染和合成
mSfConnectionHandle = mScheduler->createConnection("sf",
mPhaseOffsets->getCurrentSfOffset(),resyncCallback, [this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
});
-->makeEventThread
--> std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, connectionName);
std::make_unique<impl::EventThread>(std::move(eventThreadSource),
std::move(interceptCallback), connectionName); -->mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS {
std::unique_lock<std::mutex> lock(mMutex);
threadMain(lock);
});
....
}

线程流程图

img

对于我们而言需要知道的就是onVsyncReceive后会经过addResyncSample->updateModel 来到DispSyncThread线程的一直走到onVsyncEvent然后走到mSFEventThreadsendEvent,这个时候我们的MessageQueue就会收到消息,派发INVALID的消息然后决策是否需要刷新;

虽然说系统每秒有60个HW Vsync,但不代表APP和Vsync在每个Vsync都要更新画面,因为在Android里面,是根据software VSYN(Vsync-sf和Vsync-app)来更新画面,Software Vsync根据HwVsync过去发生的时间推测未来发生的时间,因此当APP或SF利用requestNextVsync的时候才会触发Vsync-sf或VSYNC-app;当SW Vsync和硬件Vsync误差无法接受的时候,就会重新打开硬件Vsync,来重新调节SW vsync

消息处理

INVALIDATE消息:用于处理Layer或者Display属性的变化以及Layer对应的buffer的更新

1
2
1.Layer或者Display属性的更新通过调用handleMessageTransaction()处理
2.buffer的更新通过调用handleMessageInvalidate()处理

当做完这一步后会去决策是否要进行刷新;

REFRESH消息:表示SurfaceFlinger需要进行一次合成操作(Refresh),通过handleMessageRefresh()实现;主要有三种情况:

1
2
3
1.Layer属性的变化导致window state发生变化
2.Layer有新的buffer到来
3,HWC请求进行一次repaint

如果这三种情况之一发生,则置refreshNeeded为true,调用signalRresh发出MessgaeQueue:REFRESH消息

当Vsync信号来之前,Layer或者Display属性的变化会做本地保存,只有当Vsyn信号到来时,SurfaceFlinger才会通过INVALIDATE和REFRESH消息来做统一的合并渲染和输出的处理工作;

1559196614903

代码流程如下:

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
void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS {
switch (what) {
case MessageQueue::INVALIDATE: {
if (hwcFrameMissed && !gpuFrameMissed) {
signalLayerUpdate();
-->connection->resyncCallback();
break;
}
handleMessageTransaction()
handleMessageInvalidate()
-->handlePageFlip();
//从bufferqueue中取出下一个图形缓冲区,就好像翻页一样;
//该函数主要是从各个layer对应的BufferQueue中拿图形缓冲区资料,并根据内容更新脏数据
-->invalidateLayerStack
-->signalRefresh
}
case MessageQueue::REFRESH: {
handleMessageRefresh();

rebuildLayerStacks();
//遍历所有layer按照Z序找到可见图层和可见区域。核心算法有region类完成。
//它拥有一个私有成员变量mStorage(Vector<Rect>类型),并封装了与,或,异或操作函数,管
//理一组合法有序的矩形区域。
//通过region可以方便的计算出多个图层叠加后的可见图层,可见区域及其大小位置

calculateWorkingSet();
//遍历所有可见图层,在hal创建影子图层参数,例如hal没有该图层即调用createLayer创建,然
//后分配合成策略,决策由GPU还是DE合成;
prepareFrame(display);
//通过调用hwc validate函数,会调用hwc中的AssignLayer函数,根据厂商的DE情况,决策是
//否是DE合成还是GPU
doComposition(display, repaintEverything);
//合成,如果GPU合成则调用OpenGLES合成到FB,否则全部可见图层参数送到DE,即调用hal的
//hwc_presentDisplay函数,调用presentDisplay获取fence; submitLayerToDisplay将显示
//Layer加到链表中然后唤醒hwc_submit_thread,
//调用setupLayer设置好送显的图层参数,再等待生成者的fence释放完成后;
//调用commitToDisplay送显,最后displayToSrceen调用ioctl完成

postComposition();
//完成合成后的一些状态处理
break;
}
}

总结

以下是一帧的大概显示流程,后续有机会在详细讲下技术细节:

​ 事件驱动:vsync-app驱动应用层绘图完毕后会回调onFrameAvaliable到SF的layer里面更新layer状态,然后调用requestVsync把mSFEventThread唤醒(应用若长期不送帧,会进入休眠状态),在下一个Vsync信号来时会往MessageQueue(MQ)队列添加invalidata消息。MQ是SF的主线程,它主要处理invalidate和refresh消息。当MQ收到Refresh消息后,就会真正的进入合成和送显的流程;关键流程就是以上所说的rebuildLayerStacks, calculateWorkingSet, prepareFrame, doComposition, postComposition

​ SF进行Refresh时,通过VrModeSwitch()判断是否处于虚拟桌面,调用prepareFrame(对应HWC的de2TryToAssignLayer)询问HWC各个图层的合成方式。

​ 接着调用drawMesh()进行重绘合成(OPENGL)和调用postFrameBuffer()提交合成的画布或这一帧。SF提交是不代表GPU已经处理完成,所以不直接送显;而是通过submitLayerToDisplay()把这一帧放入链表中,就直接返回接着处理下一帧。

​ HWC::DisplayOpr有一个线程,submitThreadLoop()循环通过从链表中拿出一帧数据,通过commitToDisplay()异步向display下发,下发前等GPU完成即fence释放;

其他

如何强制GPU合成:

1
2
3
4
5
6
service call SurfaceFlinger 1008 i32 1

确认是否生效:
venus-a1:/ # dumpsys SurfaceFlinger | grep "h/w composer"
h/w composer state:
h/w composer disable

参考资料

Android消息机制(一):概述设计架构

Android P 图形显示系统(一)硬件合成HWC2

android 8.0 Hwcomposer2 HIDL流程

Android OTreble架构-HIDL源代码分析http://zhoujinjian.cc/2018/09/28/Android O Treble 架构 - HIDL源代码分析/index.html)

Android 的窗口管理系统 (View, Canvas, WindowManager)

Android SurfaceFlinger学习之路(十一)合成layer之准备合成)