Android 显示系统:Vsync机制

典型的显示系统中,一般包括CPU、GPU、Display三个部分,
CPU负责计算帧数据,
GPU对计算好的图形数据进行渲染,渲染好后放在buffer(图像缓冲区)里,
Display负责把buffer里的数据呈现到屏幕上

一、Vsync简介:

  屏幕的刷新过程是每一行从左到右(行刷新,水平刷新,Horizontal Scanning),从上到下(屏幕刷新,垂直刷新,Vertical Scanning)。当整个屏幕刷新完毕,即一个垂直刷新周期完成,会有短暂的空白期,此时发出 VSync 信号。所以,VSync 中的 V 指的是垂直刷新中的垂直-Vertical。

  Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,VSync是Vertical Synchronization(垂直同步)的缩写,是一种在PC上很早就广泛使用的技术,可以简单的把它认为是一种定时中断。而在Android 4.1(JB)中已经开始引入VSync机制,用来同步渲染,让AppUI和SurfaceFlinger可以按硬件产生的VSync节奏进行工作。

基础概念

屏幕刷新频率:一秒内屏幕刷新的次数(一秒内显示了多少帧的图像),单位Hz。刷新频率取决于硬件。
60HZ  1000/60 = 16.666 ms 刷新一次

逐行扫描:显示器对图像从左到右,从上到下逐行扫描,顺序显示到屏幕的一个个像素点。

帧率:GPU在一秒内绘制操作的帧数,单位为fps。帧率是动态变化的。当画面禁止时,此时GPU没有绘制操作,屏幕刷新的还是buffer中的数据,即GPU最后操作的帧数据。

画面撕裂:理想情况下帧率和刷新频率保存一致,即每绘制完成一帧,显示器显示一帧。但屏幕刷新频率是固定的,而CPU/GPU写数据是不可控的。即Display在显示的过程中,buffer里的数据被CPU/GPU修改,导致画面撕裂;

Android 4.1 之前,屏幕刷新遵循 双缓存 + VSYNC机制。(注:此时VSync信号到来是不会强制CPU/GPU工作)。当VSYnc信号到来时,下一帧数据可能还没准备就绪,缓存没有交换,显示的仍是上一帧数据。即,发生了jank

二、三个方法改进显示系统

1.Vsync同步:

  

可见vsync信号没有提醒CPU/GPU工作的情况下,第二次vsync到来需要显示内容时,CPU和GPU还没有来得及准备好下一帧的数据,所以只能接着显示上一帧的数据,产生Jank!

  CPU/GPU接收vsync信号提前准备下一帧要显示的内容,所以能够及时准备好每一帧的数据,保证画面的流程。

 2.多级缓冲:

  除了Vsync的机制,Android还使用了多级缓冲的手段以优化UI流程度,例如双缓冲(A+B),在显示buffer A的数据时,CPU/GPU就开始在buffer B中准备下一帧数据:

  

  但是不能保证每一帧CPU、GPU都运行状态良好,可能由于资源抢占等性能问题导致某一帧GPU掉链子,vsync信号到来时buffer B的数据还没准备好,而此时Display又在显示buffer A的数据,导致后面CPU/GPU没有新的buffer着手准备数据,空白时间无事可做,后面Jank频出:

  

  因此用三级缓冲来提高系统对性能波动的容忍度:

  

虽然GPU在准备buffer B的数据耗时过长,第二帧Jank,但是新增1个buffer可以减少CPU和GPU在vsync同步间的空白间隙,此时CPU/GPU能够利用buffer C继续工作,所以后面就不会再产生Jank了,当然具体使用多少个buffer要根据实际硬件性能情况调整,最终目的就是解决Display的Jank产生。

 3.Vsync虚拟化(Vsync App + Vsync SurfaceFlinger):

  虽然vsync使得CPU/GPU/Display同步了,但App UI和SurfaceFlinger的工作显然是一个流水线的模型。即对于一帧内容,先等App UI画完了,SurfaceFlinger再出场对其进行合并渲染后放入framebuffer,最后整到屏幕上。而现有的VSync模型是让大家一起开始干活,这样对于同一帧内容,第一个VSync信号时App UI的数据开始准备,第二个VSync信号时SurfaceFlinger工作,第三个VSync信号时用户看到Display内容,这样就两个VSync period(每个16ms)过去了,影响用户体验。
  解决思路:SurfaceFlinger在App UI准备好数据后及时开工做合成。

  Android 4.4(KitKat)引入了VSync的虚拟化,即把硬件的VSync信号先同步到一个本地VSync模型中,再从中一分为二,引出两条VSync时间与之有固定偏移的线程。示意图如下:

  

  这样,大家工作既保持一定的节拍,又可以相互错开,一前一后保持着流水节奏。

  注意其中两个Phase offset参数(即VSYNC_EVENT_PHASE_OFFSET_NS和SF_VSYNC_EVENT_PHASE_OFFSET_NS)是可调的。

  处理流程:

  

  类型DispSync表示了一个基于硬件VSync信号的同步模型,它会根据从HWComposer来的硬件VSync信号的采样来进行同步。其它两个EventThread分别用了两个不同的虚拟VSync信号源(用DispSyncSource表示,其中包含了与真实VSync信号的偏移值),这两个VSync信号源就是被虚拟出来分别用于控制App UI和SurfaceFlinger渲染。在EventThread的线程循环中,如果有需要就会向DispSync注册相应的listener。DispSyncThread就像乐队鼓手一样控制着大家的节奏。它在主循环中会先通过已经向DispSync注册的listener计算下一个要产生的虚拟VSync信号还要多久,等待相应时间后就会调用相应listener的callback函数。这样,对于那些注册了listener的监听者来说,就好像被真实的VSync信号控制着一样。至于EventControlThread是用来向真实的VSync硬件发命令。

三、Vsync框架

 1.硬件或者软件创建vsyncThread产生vsync。
 2.DispSyncThread处理vsync,把vsync虚拟化成vsync-app和vsync-sf。
 3.vsync-app/sf按需产生(如果App和SurfaceFlinger都没有更新请求,则休眠省电):
  APP端:APP需要更新界面时发出vsync请求给EventThread(设置connection.count>=0),DispSyncThread收到vsync信号后休眠offset,然后唤醒EventThread通知APP开始渲染。
  SF端:sf请求EventThread-sf,EventThread-sf收到vsync后通知SF可以开始合成。

                            (vsync框架图)

 4.代码分析:

  4.1 创建五个线程:SurfaceFlingerThread、DispSyncThread、EventThead-App、EventThead-SF、VsyncThread,都属于SurfaceFlinger进程:

 (1)启动SurfaceFlinger主线程:android-8.0.0_r4\frameworks\native\services\surfaceflinger\main_surfaceflinger.cpp

int main(int, char**) {startHidlServices();signal(SIGPIPE, SIG_IGN);// When SF is launched in its own process, limit the number of// binder threads to 4.ProcessState::self()->setThreadPoolMaxThreadCount(4);// start the thread poolsp<ProcessState> ps(ProcessState::self());ps->startThreadPool();// instantiate surfaceflingersp<SurfaceFlinger> flinger = new SurfaceFlinger(); //其中创建了 mPrimaryDispSync 成员变量setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);set_sched_policy(0, SP_FOREGROUND);// Put most SurfaceFlinger threads in the system-background cpuset// Keeps us from unnecessarily using big cores// Do this after the binder thread pool initif (cpusets_enabled()) set_cpuset_policy(0, SP_SYSTEM);// initialize before clients can connectflinger->init(); //传入mPrimaryDispSync并创建EventThread(app/sf)、HWComposer// publish surface flingersp<IServiceManager> sm(defaultServiceManager());sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);// publish GpuServicesp<GpuService> gpuservice = new GpuService();sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);struct sched_param param = {0};param.sched_priority = 2;if (sched_setscheduler(0, SCHED_FIFO, &param) != 0) {ALOGE("Couldn't set SCHED_FIFO");}// run surface flinger in this thread (SF的主线程)flinger->run();return 0;
}

(2)new SurfaceFlinger() 时创建了成员变量 DispSync mPrimaryDispSync;  android-8.0.0_r4\frameworks\native\services\surfaceflinger\SurfaceFlinger.h

  其中 DispSync 的构造函数会启动DispSyncThread线程:

DispSync::DispSync(const char* name) :mName(name),mRefreshSkipCount(0),mThread(new DispSyncThread(name)), //创建了DispSyncThreadmIgnorePresentFences(!SurfaceFlinger::hasSyncFramework){mPresentTimeOffset = SurfaceFlinger::dispSyncPresentTimeOffset;mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);// set DispSync to SCHED_FIFO to minimize jitterstruct sched_param param = {0};param.sched_priority = 2;if (sched_setscheduler(mThread->getTid(), SCHED_FIFO, &param) != 0) {ALOGE("Couldn't set SCHED_FIFO for DispSyncThread");}reset();beginResync();if (kTraceDetailedInfo) {// If we're not getting present fences then the ZeroPhaseTracer// would prevent HW vsync event from ever being turned off.// Even if we're just ignoring the fences, the zero-phase tracing is// not needed because any time there is an event registered we will// turn on the HW vsync events.if (!mIgnorePresentFences && kEnableZeroPhaseTracer) {addEventListener("ZeroPhaseTracer", 0, new ZeroPhaseTracer());}}
}

(3)接着分析SurfaceFlinger对象,它是一个strong point,在引用时会调用其onFirstRef()方法:
void SurfaceFlinger::onFirstRef()
{//初始化消息队列,其中创建了loop和handlemEventQueue.init(this);
}

  flinger->run()的实现: android-8.0.0_r4\frameworks\native\services\surfaceflinger\SurfaceFlinger_hwc1.cpp

void SurfaceFlinger::run() {do {waitForEvent(); //其中就是调用mEventQueue.waitMessage()} while (true);
}

  waitMessage中等待AP和EventTHread给它发数据:

void MessageQueue::waitMessage() {do {IPCThreadState::self()->flushCommands();int32_t ret = mLooper->pollOnce(-1);switch (ret) {case Looper::POLL_WAKE:case Looper::POLL_CALLBACK:continue;case Looper::POLL_ERROR:ALOGE("Looper::POLL_ERROR");continue;case Looper::POLL_TIMEOUT:// timeout (should not happen)continue;default:// should not happenALOGE("Looper::pollOnce() returned unknown status %d", ret);continue;}} while (true);
}

  SurfaceFlinger初始化最重要的函数是init():

void SurfaceFlinger::init() {ALOGI(  "SurfaceFlinger's main thread ready to run. ""Initializing graphics H/W...");ALOGI("Phase offest NS: %" PRId64 "", vsyncPhaseOffsetNs);{ // Autolock scopeMutex::Autolock _l(mStateLock);// initialize EGL for the default displaymEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);eglInitialize(mEGLDisplay, NULL, NULL);// start the EventThread (创建了两个EventThread,他们的名字和offset不同)sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,vsyncPhaseOffsetNs, true, "app");mEventThread = new EventThread(vsyncSrc, *this, false);sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,sfVsyncPhaseOffsetNs, true, "sf");mSFEventThread = new EventThread(sfVsyncSrc, *this, true);// 创建sf与EventThread之间的connectionmEventQueue.setEventThread(mSFEventThread);// set EventThread and SFEventThread to SCHED_FIFO to minimize jitterstruct sched_param param = {0};param.sched_priority = 2;if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {ALOGE("Couldn't set SCHED_FIFO for SFEventThread");}if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, &param) != 0) {ALOGE("Couldn't set SCHED_FIFO for EventThread");}// Get a RenderEngine for the given display / config (can't fail)mRenderEngine = RenderEngine::create(mEGLDisplay,HAL_PIXEL_FORMAT_RGBA_8888);}

  其中 mEventQueue.setEventThread(mSFEventThread) 的实现:

//sufaceflinger/MessageQueue.cpp
void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
{mEventThread = eventThread;//创建连接,从连接获得dataChannel,把它的Fd添加到Looper,//也就是把EventThread里的一个fd传给了SF线程,//以后EventThread与SF就可以通过这个fd通信,mEvents = eventTHread->createEnvetConnection();mEventTube = mEvents->getDataChannel();mLooper->addFd(mEventTube->getFd(), 0, Looper::EVENT_INPUT,MessageQueue::cb_eventReceiver, this); //这个cb_eventRecevier很重要,它负责处理EventThread发过来的信号
}  

 (4)hwcomposer的构造函数:android-8.0.0_r4\frameworks\native\services\surfaceflinger\DisplayHardware\HWComposer_hwc1.cpp

HWComposer::HWComposer(const sp<SurfaceFlinger>& flinger,EventHandler& handler): mFlinger(flinger),mFbDev(0), mHwc(0), mNumDisplays(1),mCBContext(new cb_context),mEventHandler(handler),mDebugForceFakeVSync(false)
{for (size_t i =0 ; i<MAX_HWC_DISPLAYS ; i++) {mLists[i] = 0;}for (size_t i=0 ; i<HWC_NUM_PHYSICAL_DISPLAY_TYPES ; i++) {mLastHwVSync[i] = 0;mVSyncCounts[i] = 0;}char value[PROPERTY_VALUE_MAX];property_get("debug.sf.no_hw_vsync", value, "0");mDebugForceFakeVSync = atoi(value);bool needVSyncThread = true;// Note: some devices may insist that the FB HAL be opened before HWC.int fberr = loadFbHalModule();loadHwcModule();if (mFbDev && mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {// close FB HAL if we don't needed it.// FIXME: this is temporary until we're not forced to open FB HAL// before HWC.framebuffer_close(mFbDev);mFbDev = NULL;}// If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory.if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))&& !mFbDev) {ALOGE("ERROR: failed to open framebuffer (%s), aborting",strerror(-fberr));abort();}// these display IDs are always reservedfor (size_t i=0 ; i<NUM_BUILTIN_DISPLAYS ; i++) {mAllocatedDisplayIDs.markBit(i);}if (mHwc) {ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,(hwcApiVersion(mHwc) >> 24) & 0xff,(hwcApiVersion(mHwc) >> 16) & 0xff);if (mHwc->registerProcs) {mCBContext->hwc = this;mCBContext->procs.invalidate = &hook_invalidate;mCBContext->procs.vsync = &hook_vsync;if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))mCBContext->procs.hotplug = &hook_hotplug;elsemCBContext->procs.hotplug = NULL;memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));mHwc->registerProcs(mHwc, &mCBContext->procs);}// don't need a vsync thread if we have a hardware composerneedVSyncThread = false;// always turn vsync off when we starteventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);// the number of displays we actually have depends on the// hw composer versionif (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {// 1.3 adds support for virtual displaysmNumDisplays = MAX_HWC_DISPLAYS;} else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {// 1.1 adds support for multiple displaysmNumDisplays = NUM_BUILTIN_DISPLAYS;} else {mNumDisplays = 1;}}if (mFbDev) {ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)),"should only have fbdev if no hwc or hwc is 1.0");DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]);disp.connected = true;disp.format = mFbDev->format;DisplayConfig config = DisplayConfig();config.width = mFbDev->width;config.height = mFbDev->height;config.xdpi = mFbDev->xdpi;config.ydpi = mFbDev->ydpi;config.refresh = nsecs_t(1e9 / mFbDev->fps);disp.configs.push_back(config);disp.currentConfig = 0;} else if (mHwc) {// here we're guaranteed to have at least HWC 1.1for (size_t i =0 ; i<NUM_BUILTIN_DISPLAYS ; i++) {queryDisplayProperties(i);}}if (needVSyncThread) {// we don't have VSYNC support, we need to fake it// 如果不支持硬件Vsync则创建软件vysnc线程,它是一个sp<>,其onFirstRef()真正创建运行这个线程mVSyncThread = new VSyncThread(*this);}
}

  加载并准备hw composer模块。Sets mHwc

void HWComposer::loadHwcModule()
{hw_module_t const* module;if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) {ALOGE("%s module not found", HWC_HARDWARE_MODULE_ID);return;}int err = hwc_open_1(module, &mHwc);if (err) {ALOGE("%s device failed to initialize (%s)",HWC_HARDWARE_COMPOSER, strerror(-err));return;}if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) ||hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION ||hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) {ALOGE("%s device version %#x unsupported, will not be used",HWC_HARDWARE_COMPOSER, mHwc->common.version);hwc_close_1(mHwc);mHwc = NULL;return;}
}

 4.2 SurfaceFLinger使用vsync过程

(1)App发数据给sf,sf发请求给EventThread-sf:AP是Producer,它通过listener->onFrameAvailable() ->进入消费者 -> mFrameAvailableListener(就是Layer对象) -> 进入SF线程-> mFlinger->signalLayerUpdate() -> mEventQueue.invalidate();

//surfaceflinger/MessageQueue.cpp
void MessageQueue::invalidate() {//mEvents是sp<IDisplayEventConnection>//也就是sf线程使用connection向EventThread线程请求下一个vsync信号mEvents->requestNextVsync();
}
--->
//surfaceFlinger/EventThread.cpp
void EventThread::Connection::requestNextVsync() {mEventThread->requestrNextVsync(this);
}
--->
void EventTHread::requestNextVysnc(const sp<EventTHread::Connection>& connection) {if(connection->count < 0){//若cnt小于0,则cnt=0,然后发出广播,来唤醒某个线程,//当connection的cnt >= 0怎么它需要从EventThread得到vsync//这个函数得代码在EventThread,但是它执行在SF线程//也就是说,SF线程使用EventThread的函数向EventThread发出广播来唤醒EventThread线程connection->count = 0;mCondition.boradcast();}    }

(2)EventThread-sf发请求给DispSyncThread,EventThread里面一定有一个threadLoop: android-8.0.0_r4\frameworks\native\services\surfaceflinger\EventThread.cpp

bool EventThread::threadLoop() {DisplayEventReceiver::Event event;Vector< sp<EventThread::Connection> > signalConnections;//1,EventThread向DispSyncThread发出vsync请求//2,等待vsync  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 report this event
     // 当EventThread收到Vsync,把它转交给SF线程status_t err = conn->postEvent(event);if (err == -EAGAIN || err == -EWOULDBLOCK) {// The destination doesn't accept events anymore, it's probably// full. For now, we just drop the events on the floor.// FIXME: Note that some events cannot be dropped and would have// to be re-sent later.// Right-now we don't have the ability to do this.ALOGW("EventThread: dropping event (%08x) for connection %p",event.header.type, conn.get());} else if (err < 0) {// handle any other error on the pipe as fatal. the only// reasonable thing to do is to clean-up this connection.// The most common error we'll get here is -EPIPE.removeDisplayEventConnection(signalConnections[i]);}}return true;
}

分析waitForEvent():

//this will return when
//1, a vsync event has benn recevied
//2,there was as least one connection interested in receiving it when we started waiting
Vector< sp<EventThread::Connection > >EventThread::waitForEvent(DisplayEventReceiver::Event* event)
{//find out connections waitting for eventssize_t count = mDisplayEventConnections.size();ofr(size_t i=0; i<count; i++) {if(connection->count >= 0) {//we need vsync events because at least //one connnection is waiting for itwaitForVSync = true;}......if(waitFOrVSync){enableVSyncLocked(); //如果上面的count >= 0,代表需要得到vsync信号,然后调用enableVSyncLocked()}if(waitForVSync){......} else {//EventThread之后就会休眠等待vsyncmCondition.wait(mLock);}}
}

 enableVSyncLocked中给DisplaySyncThread设置回调,在DisplaySyncThread收到vsync信号后就调用这个回调函数:

void EventThread::enableVSyncLocked() {if(!mVsyncEnabled) {mVsyncEnabled = true;mVSyncSource->setCallback(static_cast<VSyncSource::Callback*)(this));mVSYncSource->setVSyncEnabled(true);}
}

(3)H/S vsync唤醒DispSyncThread:

//surfaceFlinger/DIsplayHardware/HWComposer_hwc1.cpp
bool HWComposer::VSyncThread::threadLoop() {clock_nanosleep();//休眠 完成后,调用它,发出vsync信号//mEventHanlder就是SurfaceFlinger,mHwc.mEventHandler.onVSyncReceived(0, next_vsync);
}
--->
//surfaceflinger/SurafceFLinger.cpp
void SurfaceFLinger::onVSyncReceived(type, nescs_t timestamp){if(type == 0 && mPrimaryHWVsyncEnabled) {//DispSync::addResyncSample => updateModelLocked() => //mThread->updateModel => mCond.signal()来唤醒某个线程,//mCond.signal()在DispSync.cpp,属于DispSYncThread,//还是之前说的套路,swVsyncThread使用DispSync的函数唤醒DispSYncThreadneedsHwVsync = mPrimaryDIspSync.addResyncSample(timestamp);}if(needsHwVsync) {enableHardwareVsync();}
}

(4)DispSyncThread发信号给EventThread,EventThread发信号给SF线程。

//surfaceflinger/DispSync.cpp
class DispSyncThread : public Thread {virtual bool threadLoop() {//计算最近的eventThread的时间,EventThread是Listener,// =>computeListenerNextEventTimeLocked targetTime = computeNextEventTimeLocked(now);//休眠if(now < targetTime) {mCond.waitRelative(mMutex, targetrTime-now);}//之后被vsync信号唤醒,获取callbackcallbackInvacations = gatherCallbackInvocationsLocked(now);if(callbackInvocations.size() > 0) {//执行callback,导致EventThread的onVsyncEvent函数被调用fireCallbackInvocations(callbackInvovcations);}}
}

  如果EventThread发现Connection的cnt >= 0,就会向DispSyncThread注册回调函数,最后会通过callback构造出Listener,而且EventThread运行时间是收到vsync之后加一个offset,fireCallbackInvocations()调用EventThread类的onVSyncEvent来唤醒EventThread线程:

//surfaceFlinger/EventThread.cpp
void EventThread::onVSyncEvent(nsecs_t timestamp) {Mutex::Autolock _l(mLock);mVSyncEvent[0].header.id = 0;mVsyncEvent[0].vsync.count++;//发出广播,唤醒EvenThread::threadLoop()向app或sf发出信号mCondition.broadcast();
}

  EventThread::threadLoop()在waitForEvent里面休眠(mCondition.wait),收到广播后被唤醒,然后调用conn->postEvent(event)向SF线程或者AP发出信号,并通过connection的fd把数据写到SF线程,同样SF线程通过fd获得数据,然后调用SF线程的处理函数。

status_t EventThread::Connection::postEvent(const DisplayEventReceiver::Event& event) {ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);return size < 0 ? status_t(size) : status_t(NO_ERROR);
}

 (5)sf线程对vsync的处理:在flinger->init()创建connection时,得到了一个fd,然后会检测fd。

   flinger->init() => MessageQueue::setEventThread:

mEventTube = mEvent->getDataChannel();
//检测fd,从fd得到数据,会调用MessageQueue::cb_eventRecevier函数
mLooper->addFd(mEventTube0>getFd(),....,MessageQueue::cb_eventRecevier, this);--->//surfaceflinger/MessageQueue.cpp
int MessageQueue::cb_eventRecevier(int fd, int event, void* data) {return queue->eventRecevier(fd, events);
}
--->
int MessageQueue::eventReceiver(int fd, int events) {mHanlder->displatchInvalidate();
}
--->
void MessageQueue::Handler::displayInvaliadate() {mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
}

SurfaceFlinger中接收并处理消息:

void MessageQueue::Handler::handleMessage(const Message& message) {switch(message.what) {...case INVALIDATE:mQueue.mFlinger->onMessageReceived(message.what);}
}--->// android-8.0.0_r4\frameworks\native\services\surfaceflinger\SurfaceFlinger_hwc1.cpp
void SurfaceFlinger::onMessageReceived(int32_t what) {ATRACE_CALL();switch (what) {case MessageQueue::INVALIDATE: {bool refreshNeeded = handleMessageTransaction(); //处理事务(设置flag,并未实际操作各个buffer)://①在handleTransactionLocked()中遍历每个Layer,执行layer->doTransaction(0)//②处理Display事务(add/remove)//③Layer角度发生了变化//④处理sf本身事务: Layer的增加或者删除refreshNeeded |= handleMessageInvalidate(); //处理各Layer的buffer更换,使原来的界面无效,并准备好新数据用来更新://①accquire next buffer//②release previous buffer//③bindTextureImageLocked() ---> glEGLImageTargetTexture2DOES() refreshNeeded |= mRepaintEverything;if (refreshNeeded) {// Signal a refresh if a transaction modified the window state,// a new buffer was latched, or if HWC has requested a full// repaintsignalRefresh(); //发出Refresh信号,导致下面的 handleMessageRefresh()函数被调用}break;}case MessageQueue::REFRESH: {handleMessageRefresh();  //①计算各Layer的可视区域//②合成显示:a.调用opengl把各个Layer的可视区域在一个内存上描绘出来//      b.使用hw composer硬件合成
break; } } }

                            (Vsync时序图)

Android 显示 一、 Vsync相关推荐

  1. Android 显示刷新机制、VSYNC和三重缓存机制

    Android 显示刷新机制.VSYNC和三重缓存机制 为了理解 APP 是如何进行渲染的,我们就必须了解手机硬件是如何工作的,也必须理解什么是 VSYNC. 首先,我们需要了解2个相关概念: 刷新率 ...

  2. Android显示系统详解

    一.显示系统的分类: 我们来思考一个问题:从普通用户角度来说,某个APP页面(例如购物APP首页)是怎么被显示到屏幕的? 首先看到的是物理屏幕,然后是屏幕中软件工程师编写的APP页面,也就是手机屏幕驱 ...

  3. Android SurfaceFlinger SW Vsync模型

    Android SurfaceFlinger Vsync这块比较复杂,最初在看这块的时候,迟迟不知道从何入手,网上看了各种SurfaceFlinger Vsync相关的博客,个人感觉紧紧是把代码流程给 ...

  4. 【转】自上而下解读Android显示流程

    同济大学 计算机系统结构硕士 107 人赞同了该文章 当我们点击"知乎"这个应用后,它是怎么在屏幕上显示出来的? 这个问题困扰我很久了,当我刚接触显示的时候,大约是十年前的事情了, ...

  5. Android显示架构

    一.术语 二.显示机制 2.1 水平和垂直同步信号 在早期的CRT显示器,电子枪从上到下逐行扫描,扫描完成后显示器就呈现一帧画面.然后电子枪回到初始位置进行下一次扫描.为了同步显示器的显示过程和系统的 ...

  6. 图文浅析之Android显示原理

    一,写在前面 本篇文章会以图文的方式介绍Android设备的显示原理,不会深入到源码去分析一些细节,阅读本篇文章会对显示原理有个感性的认识,以便更好的理解Android性能优化相关的原理. 二,为什么 ...

  7. Android 显示、隐藏状态栏和导航栏

    Android 显示.隐藏状态栏和导航栏 控制状态栏显示,Activity的主题中配置全屏属性 <item name="android:windowFullscreen"&g ...

  8. android显示多个网络图片不显示,Android显示网络图片实例

    本文实例讲述了Android显示网络图片的方法,分享给大家供大家参考.具体方法如下: 一般来说,在Android中显示一张网络图片其实是非常简单的,下面就是一个非常简单的例子: 步骤1: ① 创建你的 ...

  9. Android显示九宫图(自定义圆角,仿微信九宫格图)

    详细解析Android显示九宫图(自定义圆角,仿微信九宫格图) 这是一个自定义九宫格图片框架,里面有设置圆角大小,还有当图片一张的时候控件自定义的大小,图片的间隔,四张图片的时候图片自定义为两行两列等 ...

最新文章

  1. 团队开发中的 Git 实践
  2. list中抽出某一个字段的值_使用LINQ获取List列表中的某个字段值
  3. Python基础02-序列及通用操作
  4. (六)JS基础知识三(走进作用域和闭包)【三座大山之二,不会闭包,基本不会通过】
  5. python dll 混合_Python | 条线混合图
  6. 自动化测试——接口测试——增删改查
  7. centos mysql-dev_CentOS7 安装 mysql
  8. (转)洪小文:以科学的方式赤裸裸地剖析AI|混沌初开
  9. Python实现端口扫描
  10. 鼠标悬停微信图标显示二维码
  11. Oracle数据库启动过程详解
  12. Arm 架构的过程调用标准
  13. python输出数组类型_python输出数组中指定元素的所有索引示例
  14. 同济大学Python程序设计基础 实验七:文件
  15. jpg怎么压缩大小?jpg图片如何压缩大小kb?
  16. 做直播能有多赚钱,Python告诉你
  17. html中如何把一张图片分块,神奇图片分割软件有哪些分割模式 图片分割器如何检验能否无缝拼图...
  18. Python 汉字转化成拼音
  19. 从“最后一公里”问题谈起
  20. Android中禁止WebView滑动

热门文章

  1. 【JY】No.8力学架构国赛题目示例
  2. iFunk,即时享乐不等待
  3. 本地elasticsearch中文分词器 ik分词器安装及使用
  4. java实现滑动解锁
  5. 不忘初心,2017年加油!!
  6. currentTimeMillis测试效率
  7. 40套PSD欧美扁平化网页模板,可二次编辑开发,精品
  8. 彻底了解toString和valueOf区别
  9. ironpython安装包_安装Python包 – IronPython
  10. 【问题】fread读到的数据是0