Android 显示 一、 Vsync
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, ¶m) != 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, ¶m) != 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, ¶m) != 0) {ALOGE("Couldn't set SCHED_FIFO for SFEventThread");}if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, ¶m) != 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相关推荐
- Android 显示刷新机制、VSYNC和三重缓存机制
Android 显示刷新机制.VSYNC和三重缓存机制 为了理解 APP 是如何进行渲染的,我们就必须了解手机硬件是如何工作的,也必须理解什么是 VSYNC. 首先,我们需要了解2个相关概念: 刷新率 ...
- Android显示系统详解
一.显示系统的分类: 我们来思考一个问题:从普通用户角度来说,某个APP页面(例如购物APP首页)是怎么被显示到屏幕的? 首先看到的是物理屏幕,然后是屏幕中软件工程师编写的APP页面,也就是手机屏幕驱 ...
- Android SurfaceFlinger SW Vsync模型
Android SurfaceFlinger Vsync这块比较复杂,最初在看这块的时候,迟迟不知道从何入手,网上看了各种SurfaceFlinger Vsync相关的博客,个人感觉紧紧是把代码流程给 ...
- 【转】自上而下解读Android显示流程
同济大学 计算机系统结构硕士 107 人赞同了该文章 当我们点击"知乎"这个应用后,它是怎么在屏幕上显示出来的? 这个问题困扰我很久了,当我刚接触显示的时候,大约是十年前的事情了, ...
- Android显示架构
一.术语 二.显示机制 2.1 水平和垂直同步信号 在早期的CRT显示器,电子枪从上到下逐行扫描,扫描完成后显示器就呈现一帧画面.然后电子枪回到初始位置进行下一次扫描.为了同步显示器的显示过程和系统的 ...
- 图文浅析之Android显示原理
一,写在前面 本篇文章会以图文的方式介绍Android设备的显示原理,不会深入到源码去分析一些细节,阅读本篇文章会对显示原理有个感性的认识,以便更好的理解Android性能优化相关的原理. 二,为什么 ...
- Android 显示、隐藏状态栏和导航栏
Android 显示.隐藏状态栏和导航栏 控制状态栏显示,Activity的主题中配置全屏属性 <item name="android:windowFullscreen"&g ...
- android显示多个网络图片不显示,Android显示网络图片实例
本文实例讲述了Android显示网络图片的方法,分享给大家供大家参考.具体方法如下: 一般来说,在Android中显示一张网络图片其实是非常简单的,下面就是一个非常简单的例子: 步骤1: ① 创建你的 ...
- Android显示九宫图(自定义圆角,仿微信九宫格图)
详细解析Android显示九宫图(自定义圆角,仿微信九宫格图) 这是一个自定义九宫格图片框架,里面有设置圆角大小,还有当图片一张的时候控件自定义的大小,图片的间隔,四张图片的时候图片自定义为两行两列等 ...
最新文章
- 团队开发中的 Git 实践
- list中抽出某一个字段的值_使用LINQ获取List列表中的某个字段值
- Python基础02-序列及通用操作
- (六)JS基础知识三(走进作用域和闭包)【三座大山之二,不会闭包,基本不会通过】
- python dll 混合_Python | 条线混合图
- 自动化测试——接口测试——增删改查
- centos mysql-dev_CentOS7 安装 mysql
- (转)洪小文:以科学的方式赤裸裸地剖析AI|混沌初开
- Python实现端口扫描
- 鼠标悬停微信图标显示二维码
- Oracle数据库启动过程详解
- Arm 架构的过程调用标准
- python输出数组类型_python输出数组中指定元素的所有索引示例
- 同济大学Python程序设计基础 实验七:文件
- jpg怎么压缩大小?jpg图片如何压缩大小kb?
- 做直播能有多赚钱,Python告诉你
- html中如何把一张图片分块,神奇图片分割软件有哪些分割模式 图片分割器如何检验能否无缝拼图...
- Python 汉字转化成拼音
- 从“最后一公里”问题谈起
- Android中禁止WebView滑动