Android14显示系统 - VSYNC机制

文章目录

1、VSync完整分发与监听流程

1)vsync可以有HWC产生,也可以软件产生(线程隔一段时间,如16ms后发出信号);

2)偏移为了让SF和APP能异步工作(二级流水线);

3)APP需要向EventThread请求VSync(告知它需要VSync),然后进入睡眠等待,EventThread收到硬件或软件产生的VSync,就会通知该APP,APP开始工作产生新的界面;

4)SF类似,得到VSync信号开始合成界面;

5)

如果 app 渲染时间比较长,会不会错过合成呢? 答:通常 app 在渲染完后会通过 SF 向 HWC 请求下一次 vsync,以此保证渲染内容就算跟不上这一帧,也会再下一帧被显示。

2、数据结构

复制代码

3、VSync的初始化

复制代码
1. new SurfaceFlinger
创建消息队列
/android/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
onFirstRef()
--mEventQueue->init(this);
/android/frameworks/native/services/surfaceflinger/MessageQueue.cpp
----mLooper = new Looper(true);
----mHandler = new Handler(*this);

2.SF->init()  //五个线程的创建
SurfaceFlinger::init
/android/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
1) app线程监听器(DispSync)
--mEventThreadSource=DispSyncSource(DispSync, "app")
创建Event线程来管理监听器的变化(所有APP共用此线程,因此会有多个连接)
--mEventThread=EventThread(mEventThreadSource.get(),InterceptVSyncsCallback(),"appEventThread")
2) SF线程监听器(DispSync)
--mSfEventThreadSource=DispSyncSource(DispSync, "sf")
创建Event线程来管理监听器的变化
--mSFEventThread=EventThread(mSfEventThreadSource.get(),mInterceptor->saveVSyncEvent(),"sfEventThread")
3)建立联系
/android/frameworks/native/services/surfaceflinger/MessageQueue.cpp
--mEventQueue->setEventThread(mSFEventThread.get());
----eventThread->createEventConnection(); //创建connection
----mLooper->addFd(mEventTube.getFd(),MessageQueue::cb_eventReceiver) //后续线程mSFEventThread与SF通过fd来进行通讯, cb_eventReceiver处理vsync发过来的信号
--mVsyncModulator.setEventThread(mSFEventThread.get()); 
4)创建HWComposer(管理VSync)
--getBE().mHwc.reset(new HWComposer(std::make_unique<Hwc2::impl::Composer>(getBE().mHwcServiceName)));
--getBE().mHwc->registerCallback(this, getBE().mComposerSequenceId);


3.SF->run()
/android/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::run() {
    do {
        waitForEvent(); //等待Event唤醒
        --mEventQueue->waitMessage();
        ----mLooper->pollOnce(-1); //轮询等待
    } while (true);
}


4.HWC1和HWC2
1)HWC1和HWC2使用分布:
Android 9以前使用
/android/frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
Android 9以以上使用
/android/frameworks/native/services/surfaceflinger/DisplayHardware/HWC2.h


2)VSyncThread(hwc1使用)
class VSyncThread : public Thread {
        HWComposer& mHwc;
        mutable Mutex mLock;
        Condition mCondition;
        bool mEnabled;
        mutable nsecs_t mNextFakeVSync;
        nsecs_t mRefreshPeriod;
        virtual void onFirstRef();
        virtual bool threadLoop();
    public:
        VSyncThread(HWComposer& hwc);
        void setEnabled(bool enabled);
    };
sp<VSyncThread>                 mVSyncThread;


3)HwcVsync
/android/hardware/amlogic/hwcomposer/common/hwc/HwcVsync.cpp
HwcVsync
pthread_create(&hw_vsync_thread, NULL, vsyncThread, this);

5、EventThread的初始化
EventThread
--mThread = std::thread(&EventThread::threadMain, this);

4、surfaceFlinger使用VSync

复制代码
1.APP通知SF更新
/android/frameworks/native/services/surfaceflinger/BufferLayer.cpp
mFlinger->signalLayerUpdate();
/android/frameworks/native/services/surfaceflinger/MessageQueue.cpp
--mEventQueue->invalidate();
----mEvents->requestNextVsync();//请求Vsync
/android/frameworks/native/services/surfaceflinger/EventThread.cpp
------mEventThread->requestNextVsync(this);
--------mCondition.notify_all(); //唤醒EventThread

SF->run()
--waitForEvent();
----mEventQueue->waitMessage(); //持续等待信号
------mLooper->pollOnce(-1); //等待Looper触发

Looper触发后会调用回调函数(构造时创建)cb_eventReceiver
cb_eventReceiver(fd, events, data)
/android/frameworks/native/services/surfaceflinger/MessageQueue.cpp
------queue->eventReceiver(fd, events);
--------mHandler->dispatchInvalidate();
----------mQueue.mLooper->sendMessage();
------------handleMessage()
/android/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
--------------mQueue.mFlinger->onMessageReceived(message.what);
----------------signalLayerUpdate(); //如果frameMissed,即帧丢失,需要重新触发更新
----------------handleMessageTransaction();
----------------handleMessageInvalidate();
----------------signalRefresh();


2.EventThread的主循环
/android/frameworks/native/services/surfaceflinger/EventThread.cpp
EventThread::threadMain()
--DisplayEventReceiver::Event event;
--Vector<sp<EventThread::Connection> > signalConnections;
--signalConnections.size(); //存放注册过的connections
--signalConnections = waitForEventLocked(&lock, &event); //找到所有等待VSync信号的connections
--conn->postEvent(event);//遍历所有的connections,并分发event

//mChannel为注册时的fd,通过fd给SF发送Event,唤醒SF主线程工作
----DisplayEventReceiver::sendEvents(&mChannel, &event, 1);  //发送event,Looper会执行回调cb_eventReceiver
------

如何唤醒EventThread线程?
void EventThread::onVSyncEvent(nsecs_t timestamp) {
    std::lock_guard<std::mutex> lock(mMutex);
    mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
    mVSyncEvent[0].header.id = 0;
    mVSyncEvent[0].header.timestamp = timestamp;
    mVSyncEvent[0].vsync.count++;
    mCondition.notify_all(); //唤醒threadMain工作
}
由DispSyncSource来调用唤醒
DispSyncSource->onDispSyncEvent()
--callback->onVSyncEvent()


3.DispSync主循环
/android/frameworks/native/services/surfaceflinger/DispSync.cpp
threadLoop()
--computeNextEventTimeLocked(now); //计算最近的EventThread的时间
--gatherCallbackInvocationsLocked(now); //收集响应该信号的监听者
--fireCallbackInvocations(callbackInvocations); //点燃,回调监听者注册的回调方法
/android/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
----callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime); //callback是EventThread
------callback->onVSyncEvent(when); //唤醒SF中的EventThread线程,进入EventThread主循环处理


4.当HWC产生Vsync信号时,会回调SF的onVsyncReceived方法。
SurfaceFlinger::onVsyncReceived()
/android/frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp
--getBE().mHwc->onVsync() //通过mHwc查询确保收到Vsync
/android/frameworks/native/services/surfaceflinger/DispSync.cpp
--mPrimaryDispSync.addResyncSample(timestamp);
/android/frameworks/native/services/surfaceflinger/DispSync.cpp
----mThread->updateModel(mPeriod, mPhase, mReferenceTime); 
------mCond.signal();//唤醒DispSyncThread线程,进入DispSync主循环threadLoop 工作
--enableHardwareVsync();
/android/frameworks/native/services/surfaceflinger/EventControlThread.cpp
----mEventControlThread->setVsyncEnabled(true);
------mCondition.notify_all();

在哪里注册和调用?- 当然是HWC
/android/frameworks/native/services/surfaceflinger/DisplayHardware/HWC2.cpp
Device::registerCallback(ComposerCallback* callback, int32_t sequenceId)
--mComposer->registerCallback(ComposerCallbackBridge);
----ComposerCallbackBridge->onVsync()
------mCallback->onVsyncReceived(mSequenceId, display, timestamp);

5、surfaceFlinger对vsync的处理

1)SF处理的事务?

复制代码
1、layer (管理layer的增加、内容更新、属性变化、界面角度变化)
2、display (管理display的增减)

2)数据结构

复制代码
1、SurfaceFlinger
/android/frameworks/native/services/surfaceflinger/SurfaceFlinger.h
class SurfaceFlinger{
    class State {
        LayerVector layersSortedByZ; //记录layer的vector
        DefaultKeyedVector< wp<IBinder>, DisplayDeviceState> displays; //显示器状态(增减)
    }
    
    State mDrawingState{LayerVector::StateSet::Drawing}; //上一次的状态
    State mCurrentState{LayerVector::StateSet::Current}; //当前的状态
}

2、DisplayDeviceState
/android/frameworks/native/services/surfaceflinger/DisplayDevice.h
struct DisplayDeviceState {
    bool isValid() const { return type >= 0; }
    bool isMainDisplay() const { return type == DisplayDevice::DISPLAY_PRIMARY; }
    bool isVirtualDisplay() const { return type >= DisplayDevice::DISPLAY_VIRTUAL; }

    static std::atomic<int32_t> nextDisplayId;
    int32_t displayId = nextDisplayId++;
    DisplayDevice::DisplayType type = DisplayDevice::DISPLAY_ID_INVALID;
    sp<IGraphicBufferProducer> surface;
    uint32_t layerStack = DisplayDevice::NO_LAYER_STACK; //显示器id,比如DISPLAY_PRIMARY
}

3、Layer
/android/frameworks/native/services/surfaceflinger/Layer.h
class Layer {
    struct State {
        uint32_t layerStack; //显示器id,表示layer在哪个显示器显示
        int32_t sequence; // changes when visible regions can change 记录visible regions的变化,比如大小变化
    }
}

3)Buffer的状态图

4)重要的处理函数

复制代码
1.处理入口
/android/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
mQueue.mFlinger->onMessageReceived(message.what);
--signalLayerUpdate(); //如果frameMissed,即帧丢失,需要重新触发更新
--handleMessageTransaction();
--handleMessageInvalidate();
--signalRefresh(); //


2. 主要在onMessageReceived处理
/android/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
mQueue.mFlinger->onMessageReceived(message.what);
--signalLayerUpdate(); //如果frameMissed,即帧丢失,需要重新触发更新
--handleMessageTransaction();
--handleMessageInvalidate();
--signalRefresh();


3. handleMessageTransaction 处理消息事务,设置相关flag
/android/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
handleTransaction(transactionFlags); 
--handleTransactionLocked(transactionFlags);
1) layer相关
----layer->getTransactionFlags(eTransactionNeeded); //收集layer的变化、状态,后续根据这些标记来进行实际的处理
----mVisibleRegionsDirty = true;
2) display相关处理(处理增减变化)
----layer->updateTransformHint(disp);
3)处理sf本身的事务,layer的增减
----invalidateLayerStack(layer, visibleReg);
----commitTransaction(); //提交处理结果
----updateCursorAsync(); 
------layer->updateCursorPosition(displayDevice); //更新鼠标位置


4.handleMessageInvalidate  是原来的界面数据无效,并准备好新数据,用来更换
handlePageFlip();
--layer->hasQueuedFrame() //需要更新layer
----mLayersWithQueuedFrames.push_back(layer); //放入队列
/android/frameworks/native/services/surfaceflinger/BufferLayer.cpp
--layer->latchBuffer(visibleRegions, latchTime) //锁定Buffer
----updateResult == BufferLayerConsumer::BUFFER_REJECTED //拒绝更新处理
/android/frameworks/native/services/surfaceflinger/BufferLayerConsumer.cpp
----mConsumer->updateTexImage()
------acquireBufferLocked(); // Acquire the next buffer. 请求下一个buffer
/android/frameworks/native/libs/gui/ConsumerBase.cpp
--------ConsumerBase::acquireBufferLocked
--------mImages[item->mSlot] = new Image(item->mGraphicBuffer, mRE);
/android/frameworks/native/libs/gui/BufferQueueConsumer.cpp
----------mConsumer->acquireBuffer()
------updateAndReleaseLocked(); // Release the previous buffer. 释放之前的buffer
/android/frameworks/native/libs/gui/GLConsumer.cpp
--------releaseBufferLocked()
/android/frameworks/native/libs/gui/ConsumerBase.cpp
----------mConsumer->releaseBuffer()
------bindTextureImageLocked();   //使用GL库来处理界面数据,准备数据
--------mCurrentTextureImage->createIfNeeded(imageCrop)
/android/frameworks/native/services/surfaceflinger/RenderEngine/Image.cpp
----------mEGLImage = eglCreateImageKHR() //调用GL库函数处理
--invalidateLayerStack(layer, dirty);

5.signalRefresh
--mEventQueue->refresh(); //发送refresh消息

最终在onMessageReceived处理
/android/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
onMessageReceived()
--handleMessageRefresh(); //正式进入界面数据的处理 - 合成

6、Region介绍

1)基础概念

复制代码
Android SurfaceFlinger 理解Region:
https://blog.csdn.net/vviccc/article/details/104599425

Rect代表一个矩形区域
Region它代表屏幕上的一个区域,它是由一个或多个 Rect(矩形)组成的;从上到下,从左到右排序;
span也是一个区域的概念,也是由一个或多个 Rect 组成,可以认为它是一种特殊的 Region ;

示意图

2)数据结构

APP页面的层级关系

经过不同的上下左右组合,最终造成各种显示效果,这些需要软件算法处理

3)region的操作

复制代码
1)
intersect 相交
subtract 减去

2)region的属性
1.opaque:不透明
2.transparent:全透明
3.translucent:半透明

region的操作指的是合并组合rect的过程
1)
/android/frameworks/native/libs/ui/Region.cpp
enum {
    op_nand = region_operator<Rect>::op_nand,
    op_and  = region_operator<Rect>::op_and,
    op_or   = region_operator<Rect>::op_or,
    op_xor  = region_operator<Rect>::op_xor
};

比如
r1.andSelf(r2) // 得出r1与r2共同部分

2)
Vector<Rect> mStorage; //存放region的所有Rect,最后一项保存边界

3)
const   Region      merge(const Rect& rhs) const;
const   Region      mergeExclusive(const Rect& rhs) const;
const   Region      intersect(const Rect& rhs) const;
const   Region      subtract(const Rect& rhs) const;

示意图:

4)T-Junction

复制代码
1)顶点A处的插值点在图形转换后,并不能保证与顶点 A 完全重合,所以在生成的图像中 T-Junction 处产生亮点,与周围像素不协调。

2)Android系统使用以下函数进行消除
Region Region::createTJunctionFreeRegion(const Region& r) {}

7、rebuildLayerStacks

复制代码
1、负责重建每个显示设备的可见图层列表,决定了哪些图层需要在屏幕上显示,以及它们的叠放顺序,为合成工作做好准备

2、mVisibleRegionsDirty在以前情况被设置:
图层状态变化:如新增、移除、改变位置/大小、透明度变化。
显示设备变化:如屏幕旋转、分辨率切换。

3、rebuildLayerStacks() 和 computeVisibleRegions()
// rebuild the visible layer list per screen
/android/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
rebuildLayerStacks()
--Region opaqueRegion; //完全不透明区域,其下方的图层会被完全覆盖,合成时可以跳过,节省计算资源
--Region dirtyRegion; //需要重绘的区域
--Vector<sp<Layer>> layersSortedByZ; //设置可见图层的有序列表。
--Vector<sp<Layer>> layersNeedingFences;
遍历每个有效的DisplayDevice,计算它们的可见区域
--computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion); //计算可视区域
----Region aboveOpaqueLayers; //上层不透明区域
----Region aboveCoveredLayers; //上层覆盖区
//如果可见,则加入
--layersSortedByZ.add(layer);
//如果不可见,则销毁
--layer->destroyHwcLayer()
//将计算出的列表和区域设置回显示设备对象,供后续 composite 阶段使用:
--displayDevice->dirtyRegion.orSelf(dirtyRegion); 

4.遍历顺序
从最顶层(如一个对话框)开始,向最底层(如壁纸)遍历。这是算法的关键,因为底层图层的可见性完全取决于它上面所有图层的叠加情况。

5.计算四个核心区域
visibleRegion:图层在屏幕上可能可见的总范围(其自身边界)。
transparentRegion:图层自身声明为完全透明的区域(一个优化提示,但应用可能不遵守)。
opaqueRegion:图层完全不透明的区域(需满足不透明、无复杂变换、Alpha=1.0)。
coveredRegion:被所有上层图层(无论透明与否)覆盖的区域。这是 visibleRegion 与 aboveCoveredLayers 的交集。

6.可见性的决定性裁剪
一个图层的最终可见区域,需要从它的 visibleRegion 中减去它上面所有不透明图层占据的区域(aboveOpaqueLayers)。因为不透明区域会完全遮挡其下方的任何内容。

7.脏区域 (dirty) 的计算
这是性能优化的核心,决定了哪些屏幕区域必须被重绘。计算分为两种情况:
1)内容脏 (contentDirty): 图层自身内容变了(如视频播放下一帧),则其整个 visibleRegion 以及旧的可见区域都标记为脏。
2)可见性变化: 这是算法最巧妙的部分。它通过对比新旧的"暴露区域"来计算脏区。
1、暴露区域 (exposed): 图层可见且未被覆盖的部分,即 visibleRegion - coveredRegion。这是图层真正在屏幕上露出来的部分。
2、脏区 = (新暴露的区域 - 旧暴露的区域) | (新可见区域与旧覆盖区域的交集)。
简单理解就是:① 新露出来的区域要重绘;② 之前被覆盖、现在变成可见的区域也要重绘。

8.算法输出
outOpaqueRegion:所有图层不透明区域的并集(aboveOpaqueLayers)。这个信息对后续的合成策略至关重要,因为在不透明区域下方的任何图层都完全不需要被合成,可以节省大量计算。
outDirtyRegion:所有图层的脏区域并集,作为 rebuildLayerStacks 的 dirtyRegion 输出,最终传递给合成器 (composite),指导其只合成屏幕中真正发生变化的部分。
相关推荐
泡泡以安8 小时前
Android 逆向实战:从零突破某电商 App 登录接口全参数加密
android·爬虫·安卓逆向
2501_944525549 小时前
Flutter for OpenHarmony 个人理财管理App实战 - 预算详情页面
android·开发语言·前端·javascript·flutter·ecmascript
清蒸鳜鱼10 小时前
【Mobile Agent——Droidrun】MacOS+Android配置、使用指南
android·macos·mobileagent
2501_9159184110 小时前
HTTPS 代理失效,启用双向认证(mTLS)的 iOS 应用网络怎么抓包调试
android·网络·ios·小程序·https·uni-app·iphone
峥嵘life11 小时前
Android EDLA CTS、GTS等各项测试命令汇总
android·学习·elasticsearch
Cobboo11 小时前
i单词上架鸿蒙应用市场之路:一次从 Android 到 HarmonyOS 的完整实战
android·华为·harmonyos
天下·第二11 小时前
达梦数据库适配
android·数据库·adb
定偶11 小时前
MySQL知识点
android·数据结构·数据库·mysql
iwanghang11 小时前
Android Studio 2023.2.1 新建项目 不能选择Java 解决方法
android·ide·android studio
似霰11 小时前
JNI 编程指南10——从内存角度看引用类型
android·jni