前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android--Vsync代码分析(二)

Android--Vsync代码分析(二)

作者头像
用户9732312
发布2022-05-13 20:03:34
5360
发布2022-05-13 20:03:34
举报
文章被收录于专栏:ADAS性能优化

我们来看看其代码的实现.

void SurfaceFlinger::init()

{

// start the EventThread

sp<VSyncSource>vsyncSrc = new DispSyncSource(&mPrimaryDispSync,

vsyncPhaseOffsetNs, true,"app");

mEventThread = newEventThread(vsyncSrc);

sp<VSyncSource>sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,

sfVsyncPhaseOffsetNs, true, "sf");

mSFEventThread= new EventThread(sfVsyncSrc);

mEventQueue.setEventThread(mSFEventThread);

}

当surfaceFlinger 初始化时,其创建了两个DispSyncSource 和两个EventThread.一个用于APP, 而另一个用于SurfaceFlinger 本身.我们知道DispSyncSource和DispSync协同工作, 共同完成Vsyncevent的fire.而EventThread会triggerApp draw frame和surfaceFlinger合成”dirty”layer当SW-VSYNCevent 产生时.

我们在这里列出DispSyncSource和Vsync-sf 有关系的code.

class DispSyncSource : publicVSyncSource, private DispSync::Callback {

public:

DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,

virtual void setVSyncEnabled(bool enable) {

Mutex::Autolock lock(mVsyncMutex);

if (enable) {

status_t err =mDispSync->addEventListener(mPhaseOffset,

static_cast<DispSync::Callback*>(this));

….

} else {

status_t err = mDispSync->removeEventListener(

static_cast<DispSync::Callback*>(this));

….

}

virtual void onDispSyncEvent(nsecs_t when) {

sp<VSyncSource::Callback> callback;

{

Mutex::Autolocklock(mCallbackMutex);

callback = mCallback;

if (mTraceVsync) {

mValue = (mValue + 1) % 2;

ATRACE_INT(mVsyncEventLabel.string(), mValue);

}

}

if (callback != NULL) {

callback->onVSyncEvent(when);

}

}

….

}

其中最重要的两个function是setVSyncEnabled(bool enable)和onDispSyncEvent(nsecs_twhen). setVSyncEnabled()的功能是把自己注册到DispSync(enable=true)中或者从DispSync中remove掉自己(enale=false),当DispSync产生了SW-VSYNCevent时,会check对SW-VSYNC感兴趣的DispSyncSource并回调其onDispSyncEvent().onDispSyncEvent()主要的功能一是enableVsync-sf 在sytrace中,一是callback EventThread中的onVSyncEvent(),从而触发SurfaceFlinger 合成所有更新的layer.

下面我们来看看EventThread 的重要code

EventThread::Connection::Connection(

constsp<EventThread>& eventThread)

: count(-1),mEventThread(eventThread), mChannel(new BitTube())

{

}

sp<EventThread::Connection> EventThread::createEventConnection()const {

return new Connection(const_cast<EventThread*>(this));

}

status_tEventThread::registerDisplayEventConnection(

constsp<EventThread::Connection>& connection) {

Mutex::Autolock _l(mLock);

mDisplayEventConnections.add(connection);

}

void EventThread::requestNextVsync(

if (connection->count < 0) {

connection->count = 0;

mCondition.broadcast();

}

}

void EventThread::onVSyncEvent(nsecs_t timestamp){

Mutex::Autolock _l(mLock);

mCondition.broadcast();

}

bool EventThread::threadLoop() {

DisplayEventReceiver::Event event;

Vector< sp<EventThread::Connection> > signalConnections;

signalConnections =waitForEvent(&event);

// dispatch events to listeners...

const size_t count= signalConnections.size();

for (size_t i=0 ; i<count ; i++) {

const sp<Connection>&conn(signalConnections[i]);

// now see if we still need to reportthis event

status_t err = conn->postEvent(event);

}

// This will return when (1) avsync event has been received, and (2) there was

// at least one connectioninterested in receiving it when we started waiting.

Vector<sp<EventThread::Connection> > EventThread::waitForEvent(

DisplayEventReceiver::Event* event)

{

Mutex::Autolock _l(mLock);

Vector< sp<EventThread::Connection>> signalConnections;

do {

….

// find out connections waiting forevents

size_t count = mDisplayEventConnections.size();

for (size_t i=0 ; i<count ; i++) {

….

if (connection->count >= 0) {

// we need vsync eventsbecause at least

// one connection iswaiting for it

waitForVSync = true;

if (timestamp) {

if(connection->count == 0) {

// fired this timearound

connection->count = -1;

signalConnections.add(connection);

}

// Here we figure out if we need toenable or disable vsyncs

if (timestamp && !waitForVSync) {

// we received a VSYNC but we haveno clients

// don't report it, and disableVSYNC events

disableVSyncLocked();

} else if (!timestamp &&waitForVSync) {

// we have at least one client, sowe want vsync enabled

// (TODO: this function is calledright after we finish

// notifying clients of a vsync, sothis call will be made

// at the vsync rate, e.g.60fps. If we can accurately

// track the currentstate we could avoid making this call

// so often.)

enableVSyncLocked();

}

if (!timestamp &&!eventPending) {

// wait for something to happen

if (waitForVSync) {

if (mCondition.waitRelative(mLock, timeout) ==TIMED_OUT) {

…..

}

} else {

// Nobody is interested invsync, so we just want to sleep.

mCondition.wait(mLock);

}

}

} while (signalConnections.isEmpty());

return signalConnections;

}

我们列出了EventThread 的重要function.下面一一说明其功能.

  • EventThread::Connection::Connection() Connection的构造函数.用于进程间的通信by BitTube..在此处主要是搭建一个通路(BitTube)来完成client(App 或SurfaceFlinger)对Vsyncevent 事件的请求(通过requestNextVsync())和EventThread把SW-Vsyncevent callback 到其感兴趣的client.需要注意的是App是通过SurfaceFlinger::createDisplayEventConnection()创建此连接的.而sufaceflinge是在其初始化时callEventQueue.setEventThread(mSFEventThread) 创建的. 所以对App 的EventThread 来说可能有多个connection ,也有可能没有.而对sufaceflinger 目前来说有且只有一个.
  • sp<EventThread::Connection>EventThread::createEventConnection() 创建Connection 连接.
  • status_tEventThread::registerDisplayEventConnection() 如其名所描述.其功能是把创建的Connection注册到一个容器中.当SW-VSYNCevent 发生时,EventThread会从Connection注册的容器中,找到那些对SW-VSYNCevent感兴趣的connection并把vsyncevent 通过BitTube传到client.
  • void EventThread::requestNextVsync() Clinet 端通过Connectioncall 这函数通知EventThread,其对SW-SYNCevent的请求.
  • voidEventThread::onVSyncEvent(nsecs_t timestamp) 当SW-VSYNCEVENT 发生时,DispSyncSource 会call此函数,告知EventThread,Vsyncevent已经发生,如果此时有connect对Vsync 感兴趣,EventThread便会通过connect->postEvent(event)把Vsync 事件发送到client端(App或surfaceflinger).
  • bool EventThread::threadLoop() 线程的主体函数.其完成两件事.一是把对SW-VSYNCevent 有请求并且还没有处理的connect找出来.而是把Vsyncevent通过connect通知到client.
  • Vector< sp<EventThread::Connection>> EventThread::waitForEvent() EventThread 的主要功能都在此函数里.此函数由threadLoop()调用.EventThread 在大部分时间里是sleep的.如果系统的性能比较好,那么其sleep的节奏是和SW-VSYNCevent的节奏一致.即16.6mssleep一次.然而由于其App或surfaceflinger没有Vsync的请求,其sleep的时间为更长.此函数的名为waitForEvent,其到底在等什么event?原来此函数在等待的event就是Dispsync产生的SW-SYNCevent. 其功能check所有的connect是否有Vsync事件请求根据不同的情况做如下处理.
  1. 所有的connect都没有Vsync请求,则其通过disableVSyncLocked(),disableVsync event,那么此EventThread将不会收到SW-SYNCevent,一直sleep直到有connect有Vsync请求为止.
  2. 在所有的connect中,有SW-SYNC event请求,但是当其请求SW-SYNCevent时,SW-SYNCevent还没有fire,则其通过enableVSyncLocked()enable Vsync并进入sleep.当下一个SW-SYNCevent来到时,便把所有有SW-SYNCevent请求的connection返回给threadLoop.

下图是big pic.

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-10-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Android性能优化 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档