Android11可变刷新率策略

以云看科技 2024-05-09 00:00:01
一、何为可变刷新率Android 设备运行时的刷新率是由 Android 平台控制的。应用和游戏可以通过多种方法影响刷新率 (下面会有解释),但最终结果由平台决定。尤其是当屏幕上同时有多个应用时,这一点至关重要: 平台需要满足所有应用的刷新率需求。24fps 视频播放器就是一个很好的例子。24Hz 对于视频播放来说可能很好,但对于响应式 UI 来说就很糟糕了。如果一个推送通知的动画只有 24Hz,感觉就会很扎眼。在这种情况下,平台会选择让屏幕上的内容都显示良好的刷新率。

为此,应用可能需要知道当前设备的刷新率。可以通过以下方法来实现:

SDK通过 DisplayManager.DisplayListener 注册一个显示监听器,并通过 Display.getRefreshRate 查询刷新率。NDK使用 AChoreographer_registerRefreshRateCallback 注册回调 (API 级别30)。

应用可以通过在其 Window 或 Surface 上设置帧率来影响设备刷新率。这是 Android 11 中引入的一个新功能,允许平台了解应用的渲染需求。应用可以调用以下方法之一:

SDKSurface.setFrameRateSurfaceControl.Transaction.setFrameRateNDKANativeWindow_setRrameRateASurfaceTransaction_setFrameRate

关于如何使用这些 API,请参考 帧率指南 文档。

系统会根据 Window 或 Surface 上设置的帧率选择最合适的刷新率。

二、刷新率注册

SurfaceFlinger在初始化的时候,会对mRefreshRateConfigs 进行初始化,其中getHwComposer().getConfigs()就是获取屏幕支持的刷新率.

三、刷新率区间设置和匹配

peak_refresh_rate 和 min_refresh_rate 设置命令:adb shell settings put system min_refresh_rate 60.0 //设置刷新率下限值adb shell settings put system peak_refresh_rate 120.0 //设置刷新率上限值

命令调用流程

通过adb命令修改peak_refresh_rate或者min_refresh_rate时,DisplayModeDirector.java里面的监听哨会捕捉到值的变化,调用onChange方法

OnChange()-->updateRefreshRateSettingLocked()-->updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRrefreshRate)

如上updateRefreshRateSettingLocked中,重点调用了updateVoteLocked方法,用于更新每一个优先级对应的参数(主要是该优先级下记录的刷新率变动范围).

接下来先聊聊RefreshRateRange类定义:主要定义了min和max两个成员用于记录刷新率范围.

Vote类定义:主要声明定义了七个优先级,定义了width,height,refreshrate 三个成员用于记录优先级对应的宽、高和刷新率变化范围.

Votes 结构定义以及updateVoteLocked方法:每一个display设备(默认只有一个屏)都有一个votes对象(通过getOrCreateVotesByDisplay方法获取), 而每一个votes又是一个SparseArray 数据结构(构成为一个优先级对应一个vote,<priority, vote>), updateVoteLocked方法就是用新vote(里面主要定义了新刷新率范围)更新对应优先级的vote

最后,调用了notifyDesiredDisplayModeSpecsChangedLocked(), 发送类型MSG_REFRESH_RATE_RANGE_CHANGED的消息以及mDesiredDisplayModeSpecsListener(这个全局对象后面会赋值), 触发调用mDesiredDisplayModeSpecsListener的方法onDesiredDisplayModeSpecsChanged():

mDesiredDisplayModeSpecsListener和onDesiredDisplayModesSpecsChanged()方法的定义和对应初始化流程如下:

新建DesiredDisplayModeSpecsObserver对象,并通过setDesiredDisplayModeSpecsListener赋值给mDesiredDisplayModeSpecsListener:

DesiredDisplayModeSpecsObserver类:onDesiredDisplayModesSpecsChanged()--->onDesiredDisplayModeSpecsChangedInternal();

在讲onDesiredDisplayModeSpecsChangedInternal()方法前,我们先了解下接下来要涉及到的DesiredDisplayConfigSpecs类和Votesummary类:

DesiredDisplayConfigSpecs类:主要定义了primaryRefreshRateMin,primaryRefreshRateMax---代表 surface flinger 切换刷新率的范围.appRequestRefreshRateMin, appRequestRefreshRateMax---代表app能够透过setFrameRate api设置的刷新率范围,它比primaryRrefreshRate范围要大.defaultConfig.

VoteSummary类: 主要定义了minRefreshRate和maxRrefreshRate,width,heigh.summarizeVotes方法:取传入优先级对应的刷新率refreshRateRange的交集,其中lowestConsideredPriority表示只计算优先级大于等于它的优先级对应的refreshRateRange的交集;

getVotesLocked:通过displayid获取前面更新设置的对应display的SparseArray对象数据结构(里面是各优先级以及其对应的vote对象,vote里面保存的是RefreshRateRange范围);

getDesiredDisplayModeSpecs()方法主要工作为:计算primarySummary,对所有优先级对应的refreshRateRange依次递减进行计算交集,最后得到primarySummary;计算appRequestSummary, 从APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF到最大优先级的交集,最后取其和primarySummary的合集;添加打印日志:

09-13 02:23:18.779 1034 1086 I DisplayModeDirector: updateVoteLocked(displayId=-1, priority=PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, vote=Vote{width=-1, height=-1, minRefreshRate=0.0, maxRefreshRate=120.0})09-13 02:23:18.779 1034 1086 I DisplayModeDirector: updateVoteLocked(displayId=-1, priority=PRIORITY_USER_SETTING_MIN_REFRESH_RATE, vote=Vote{width=-1, height=-1, minRefreshRate=50.0, maxRefreshRate=Infinity})09-13 02:23:18.779 1034 1086 I DisplayModeDirector: updateVoteLocked(displayId=-1, priority=PRIORITY_DEFAULT_REFRESH_RATE, vote=null)09-13 02:23:18.779 1034 1086 I DisplayModeDirector: updateVoteLocked(displayId=-1, priority=PRIORITY_USER_SETTING_PEAK_REFRESH_RATE, vote=Vote{width=-1, height=-1, minRefreshRate=0.0, maxRefreshRate=120.0})09-13 02:23:18.779 1034 1086 I DisplayModeDirector: updateVoteLocked(displayId=-1, priority=PRIORITY_USER_SETTING_MIN_REFRESH_RATE, vote=Vote{width=-1, height=-1, minRefreshRate=50.0, maxRefreshRate=Infinity})09-13 02:23:18.779 1034 1086 I DisplayModeDirector: updateVoteLocked(displayId=-1, priority=PRIORITY_DEFAULT_REFRESH_RATE, vote=null)09-13 02:23:18.779 1034 1086 I DisplayModeDirector: displayId:009-13 02:23:18.779 1034 1086 I DisplayModeDirector: sumarizeVotes:009-13 02:23:18.779 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:609-13 02:23:18.779 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:509-13 02:23:18.780 1034 1086 I DisplayModeDirector: sumarizeVotes find priority:5, vote:Vote{width=-1, height=-1, minRefreshRate=0.0, maxRefreshRate=120.0}09-13 02:23:18.780 1034 1086 I DisplayModeDirector: sumarizeVotes before summary: min:0.0 max:Infinity height:-1 width: -109-13 02:23:18.780 1034 1086 I DisplayModeDirector: sumarizeVotes after-0 summary: min:0.0 max:120.0 height:-1 width: -109-13 02:23:18.780 1034 1086 I DisplayModeDirector: sumarizeVotes after-1 summary: min:0.0 max:120.0 height:-1 width: -109-13 02:23:18.780 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:409-13 02:23:18.780 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:309-13 02:23:18.780 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:209-13 02:23:18.780 1034 1086 I DisplayModeDirector: sumarizeVotes find priority:2, vote:Vote{width=-1, height=-1, minRefreshRate=50.0, maxRefreshRate=Infinity}09-13 02:23:18.780 1034 1086 I DisplayModeDirector: sumarizeVotes before summary: min:0.0 max:120.0 height:-1 width: -109-13 02:23:18.780 1034 1086 I DisplayModeDirector: sumarizeVotes after-0 summary: min:50.0 max:120.0 height:-1 width: -109-13 02:23:18.780 1034 1086 I DisplayModeDirector: sumarizeVotes after-1 summary: min:50.0 max:120.0 height:-1 width: -109-13 02:23:18.780 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:109-13 02:23:18.780 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:009-13 02:23:18.780 1034 1086 W DisplayModeDirector: filterModes:{id=1, width=1080, height=2408, fps=50.0}09-13 02:23:18.780 1034 1086 W DisplayModeDirector: filterModes:{id=2, width=1080, height=2408, fps=60.0}09-13 02:23:18.780 1034 1086 W DisplayModeDirector: filterModes:{id=3, width=1080, height=2408, fps=90.0}09-13 02:23:18.780 1034 1086 W DisplayModeDirector: filterModes:{id=4, width=1080, height=2408, fps=120.00001}09-13 02:23:18.780 1034 1086 W DisplayModeDirector: Found available modes=[1, 2, 3, 4] with lowest priority considered PRIORITY_DEFAULT_REFRESH_RATE and constraints: width=1080, height=2408, minRefreshRate=50.0, maxRefreshRate=120.009-13 02:23:18.780 1034 1086 I DisplayModeDirector: sumarizeVotes:309-13 02:23:18.780 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:609-13 02:23:18.780 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:509-13 02:23:18.780 1034 1086 I DisplayModeDirector: sumarizeVotes find priority:5, vote:Vote{width=-1, height=-1, minRefreshRate=0.0, maxRefreshRate=120.0}09-13 02:23:18.781 1034 1086 I DisplayModeDirector: sumarizeVotes before summary: min:0.0 max:Infinity height:-1 width: -109-13 02:23:18.781 1034 1086 I DisplayModeDirector: sumarizeVotes after-0 summary: min:0.0 max:120.0 height:-1 width: -109-13 02:23:18.781 1034 1086 I DisplayModeDirector: sumarizeVotes after-1 summary: min:0.0 max:120.0 height:-1 width: -109-13 02:23:18.781 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:409-13 02:23:18.781 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:309-13 02:23:18.781 1034 1086 I DisplayModeDirector: App request range: [0 120]09-13 02:23:18.785 590 737 V RefreshRateConfigs: getRefreshRateForContent 0 layers09-13 02:23:18.887 590 590 D ha ha : #00 pc 00000000000ffdcc /system/lib64/libsurfaceflinger.so (android::scheduler::RefreshRateConfigs::constructAvailableRefreshRates()+176)09-13 02:23:18.887 590 590 D ha ha : #01 pc 000000000010004c /system/lib64/libsurfaceflinger.so (android::scheduler::RefreshRateConfigs::setDisplayManagerPolicy(android::scheduler::RefreshRateConfigs::Policy const&)+464)09-13 02:23:18.887 590 590 D ha ha : #02 pc 00000000001278d4 /system/lib64/libsurfaceflinger.so (android::SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(android::sp<android::DisplayDevice> const&, std::__1::optional<android::scheduler::RefreshRateConfigs::Policy> const&, bool)+432)09-13 02:23:18.887 590 590 D ha ha : #03 pc 00000000001383f0 /system/lib64/libsurfaceflinger.so (_ZNSt3__120__packaged_task_funcIZN7android14SurfaceFlinger28setDesiredDisplayConfigSpecsERKNS1_2spINS1_7IBinderEEEiffffE4$_63NS_9allocatorIS8_EEFivEEclEv$ed74649543c784cf7bf71a82a57ab79d+300)09-13 02:23:18.888 590 590 D ha ha : #08 pc 000000000010db58 /system/lib64/libsurfaceflinger.so (android::SurfaceFlinger::run()+20)09-13 02:23:18.889 590 590 V RefreshRateConfigs: constructAvailableRefreshRates: default 0 group -1 primaryRange=[50.00 120.00] appRequestRange=[0.00 120.00]09-13 02:23:18.889 590 590 V RefreshRateConfigs: getSortedRefreshRateList: config 3 added to list policy09-13 02:23:18.889 590 590 V RefreshRateConfigs: getSortedRefreshRateList: config 2 added to list policy09-13 02:23:18.889 590 590 V RefreshRateConfigs: getSortedRefreshRateList: config 1 added to list policy09-13 02:23:18.889 590 590 V RefreshRateConfigs: getSortedRefreshRateList: config 0 added to list policy09-13 02:23:18.889 590 590 V RefreshRateConfigs: primary refresh rates: 50fps 60fps 90fps 120fps09-13 02:23:18.890 590 590 V RefreshRateConfigs: getSortedRefreshRateList: config 3 added to list policy09-13 02:23:18.890 590 590 V RefreshRateConfigs: getSortedRefreshRateList: config 2 added to list policy09-13 02:23:18.890 590 590 V RefreshRateConfigs: getSortedRefreshRateList: config 1 added to list policy09-13 02:23:18.890 590 590 V RefreshRateConfigs: getSortedRefreshRateList: config 0 added to list policy09-13 02:23:18.890 590 590 V RefreshRateConfigs: app request refresh rates: 50fps 60fps 90fps 120fps09-13 02:23:18.891 590 590 V SurfaceFlinger: Setting desired display config specs: defaultConfig: 0 primaryRange: [50 120] expandedRange: [0 120]09-13 02:23:18.891 590 590 V RefreshRateConfigs: getRefreshRateForContent 0 layers09-13 02:23:18.891 590 590 V SurfaceFlinger: trying to switch to Scheduler preferred config 3 (120fps)09-13 02:23:18.891 590 590 V SurfaceFlinger: switching to Scheduler preferred config 309-13 02:23:18.891 590 590 V SurfaceFlinger: setDesiredActiveConfig(120fps)09-13 02:23:18.892 590 737 V SurfaceFlinger: setDesiredActiveConfig(120fps)09-13 02:23:18.893 590 590 V SurfaceFlinger: performSetActiveConfig changing active config to 3(120fps)09-13 02:23:18.898 590 590 V SurfaceFlinger: performSetActiveConfig changing active config to 3(120fps)09-13 02:26:05.924 1034 1087 I DisplayModeDirector: updateVoteLocked(displayId=0, priority=PRIORITY_APP_REQUEST_REFRESH_RATE, vote=Vote{width=-1, height=-1, minRefreshRate=60.0, maxRefreshRate=60.0})09-13 02:26:05.924 1034 1087 I DisplayModeDirector: updateVoteLocked(displayId=0, priority=PRIORITY_APP_REQUEST_SIZE, vote=Vote{width=1080, height=2408, minRefreshRate=0.0, maxRefreshRate=Infinity})09-13 02:26:05.928 590 590 V RefreshRateConfigs: getRefreshRateForContent 2 layers09-13 02:26:05.928 590 590 V RefreshRateConfigs: refreshRate:50fps,50.0009-13 02:26:05.928 590 590 V RefreshRateConfigs: refreshRate:60fps,60.0009-13 02:26:05.928 590 590 V RefreshRateConfigs: refreshRate:90fps,90.0009-13 02:26:05.928 590 590 V RefreshRateConfigs: refreshRate:120fps,120.0009-13 02:26:05.928 590 590 V RefreshRateConfigs: Calculating score for NavigationBar0#0 (Max, weight 0.06)09-13 02:26:05.928 590 590 V RefreshRateConfigs: NavigationBar0#0 (Max, weight 0.06) gives 50fps score of 0.1709-13 02:26:05.928 590 590 V RefreshRateConfigs: NavigationBar0#0 (Max, weight 0.06) gives 60fps score of 0.2509-13 02:26:05.928 590 590 V RefreshRateConfigs: NavigationBar0#0 (Max, weight 0.06) gives 90fps score of 0.5609-13 02:26:05.928 590 590 V RefreshRateConfigs: NavigationBar0#0 (Max, weight 0.06) gives 120fps score of 1.0009-13 02:26:05.928 590 590 V RefreshRateConfigs: Calculating score for com.youku.phone/com.youku.v2.HomePageEntry#0 (Max, weight 1.00)09-13 02:26:05.928 590 590 V RefreshRateConfigs: com.youku.phone/com.youku.v2.HomePageEntry#0 (Max, weight 1.00) gives 50fps score of 0.1709-13 02:26:05.928 590 590 V RefreshRateConfigs: com.youku.phone/com.youku.v2.HomePageEntry#0 (Max, weight 1.00) gives 60fps score of 0.2509-13 02:26:05.928 590 590 V RefreshRateConfigs: com.youku.phone/com.youku.v2.HomePageEntry#0 (Max, weight 1.00) gives 90fps score of 0.5609-13 02:26:05.928 590 590 V RefreshRateConfigs: com.youku.phone/com.youku.v2.HomePageEntry#0 (Max, weight 1.00) gives 120fps score of 1.0009-13 02:26:05.928 590 590 V RefreshRateConfigs: 120fps scores 1.0609-13 02:26:05.928 590 590 V RefreshRateConfigs: 90fps scores 0.6009-13 02:26:05.928 590 590 V RefreshRateConfigs: 60fps scores 0.2609-13 02:26:05.928 590 590 V RefreshRateConfigs: 50fps scores 0.1809-13 02:26:05.940 1034 1086 I DisplayModeDirector: displayId:009-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes:009-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:609-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:509-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes find priority:5, vote:Vote{width=-1, height=-1, minRefreshRate=0.0, maxRefreshRate=120.0}09-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes before summary: min:0.0 max:Infinity height:-1 width: -109-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes after-0 summary: min:0.0 max:120.0 height:-1 width: -109-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes after-1 summary: min:0.0 max:120.0 height:-1 width: -109-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:409-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes find priority:4, vote:Vote{width=1080, height=2408, minRefreshRate=0.0, maxRefreshRate=Infinity}09-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes before summary: min:0.0 max:120.0 height:-1 width: -109-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes after-0 summary: min:0.0 max:120.0 height:-1 width: -109-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes after-1 summary: min:0.0 max:120.0 height:2408 width: 108009-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:309-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes find priority:3, vote:Vote{width=-1, height=-1, minRefreshRate=60.0, maxRefreshRate=60.0}09-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes before summary: min:0.0 max:120.0 height:2408 width: 108009-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes after-0 summary: min:60.0 max:60.0 height:2408 width: 108009-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes after-1 summary: min:60.0 max:60.0 height:2408 width: 108009-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:209-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes find priority:2, vote:Vote{width=-1, height=-1, minRefreshRate=50.0, maxRefreshRate=Infinity}09-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes before summary: min:60.0 max:60.0 height:2408 width: 108009-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes after-0 summary: min:60.0 max:60.0 height:2408 width: 108009-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes after-1 summary: min:60.0 max:60.0 height:2408 width: 108009-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:109-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:009-13 02:26:05.940 1034 1086 W DisplayModeDirector: filterModes:{id=1, width=1080, height=2408, fps=50.0}09-13 02:26:05.940 1034 1086 W DisplayModeDirector: Discarding mode 1, outside refresh rate bounds: minRefreshRate=60.0, maxRefreshRate=60.0, modeRefreshRate=50.009-13 02:26:05.940 1034 1086 W DisplayModeDirector: filterModes:{id=2, width=1080, height=2408, fps=60.0}09-13 02:26:05.940 1034 1086 W DisplayModeDirector: filterModes:{id=3, width=1080, height=2408, fps=90.0}09-13 02:26:05.940 1034 1086 W DisplayModeDirector: Discarding mode 3, outside refresh rate bounds: minRefreshRate=60.0, maxRefreshRate=60.0, modeRefreshRate=90.009-13 02:26:05.940 1034 1086 W DisplayModeDirector: filterModes:{id=4, width=1080, height=2408, fps=120.00001}09-13 02:26:05.940 1034 1086 W DisplayModeDirector: Discarding mode 4, outside refresh rate bounds: minRefreshRate=60.0, maxRefreshRate=60.0, modeRefreshRate=120.0000109-13 02:26:05.940 1034 1086 W DisplayModeDirector: Found available modes=[2] with lowest priority considered PRIORITY_DEFAULT_REFRESH_RATE and constraints: width=1080, height=2408, minRefreshRate=60.0, maxRefreshRate=60.009-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes:309-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:609-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:509-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes find priority:5, vote:Vote{width=-1, height=-1, minRefreshRate=0.0, maxRefreshRate=120.0}09-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes before summary: min:0.0 max:Infinity height:-1 width: -109-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes after-0 summary: min:0.0 max:120.0 height:-1 width: -109-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes after-1 summary: min:0.0 max:120.0 height:-1 width: -109-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:409-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes find priority:4, vote:Vote{width=1080, height=2408, minRefreshRate=0.0, maxRefreshRate=Infinity}09-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes before summary: min:0.0 max:120.0 height:-1 width: -109-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes after-0 summary: min:0.0 max:120.0 height:-1 width: -109-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes after-1 summary: min:0.0 max:120.0 height:2408 width: 108009-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes: priority:309-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes find priority:3, vote:Vote{width=-1, height=-1, minRefreshRate=60.0, maxRefreshRate=60.0}09-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes before summary: min:0.0 max:120.0 height:2408 width: 108009-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes after-0 summary: min:60.0 max:60.0 height:2408 width: 108009-13 02:26:05.940 1034 1086 I DisplayModeDirector: sumarizeVotes after-1 summary: min:60.0 max:60.0 height:2408 width: 108009-13 02:26:05.940 1034 1086 I DisplayModeDirector: App request range: [60 60]09-13 02:26:05.976 590 590 D ha ha : #00 pc 00000000000ffdcc /system/lib64/libsurfaceflinger.so (android::scheduler::RefreshRateConfigs::constructAvailableRefreshRates()+176)09-13 02:26:05.976 590 590 D ha ha : #01 pc 000000000010004c /system/lib64/libsurfaceflinger.so (android::scheduler::RefreshRateConfigs::setDisplayManagerPolicy(android::scheduler::RefreshRateConfigs::Policy const&)+464)09-13 02:26:05.976 590 590 D ha ha : #02 pc 00000000001278d4 /system/lib64/libsurfaceflinger.so (android::SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(android::sp<android::DisplayDevice> const&, std::__1::optional<android::scheduler::RefreshRateConfigs::Policy> const&, bool)+432)09-13 02:26:05.976 590 590 D ha ha : #03 pc 00000000001383f0 /system/lib64/libsurfaceflinger.so (_ZNSt3__120__packaged_task_funcIZN7android14SurfaceFlinger28setDesiredDisplayConfigSpecsERKNS1_2spINS1_7IBinderEEEiffffE4$_63NS_9allocatorIS8_EEFivEEclEv$ed74649543c784cf7bf71a82a57ab79d+300)09-13 02:26:05.976 590 590 D ha ha : #08 pc 000000000010db58 /system/lib64/libsurfaceflinger.so (android::SurfaceFlinger::run()+20)09-13 02:26:05.976 590 590 V RefreshRateConfigs: constructAvailableRefreshRates: default 1 group -1 primaryRange=[60.00 60.00] appRequestRange=[60.00 60.00]09-13 02:26:05.976 590 590 V RefreshRateConfigs: getSortedRefreshRateList: config 1 added to list policy09-13 02:26:05.976 590 590 V RefreshRateConfigs: primary refresh rates: 60fps09-13 02:26:05.976 590 590 V RefreshRateConfigs: getSortedRefreshRateList: config 1 added to list policy09-13 02:26:05.976 590 590 V RefreshRateConfigs: app request refresh rates: 60fps09-13 02:26:05.976 590 590 V SurfaceFlinger: Setting desired display config specs: defaultConfig: 1 primaryRange: [60 60] expandedRange: [60 60]09-13 02:26:05.976 590 590 V RefreshRateConfigs: getRefreshRateForContent 2 layers09-13 02:26:05.976 590 590 V RefreshRateConfigs: refreshRate:60fps,60.0009-13 02:26:05.976 590 590 V RefreshRateConfigs: Calculating score for NavigationBar0#0 (Max, weight 0.06)09-13 02:26:05.976 590 590 V RefreshRateConfigs: Calculating score for com.youku.phone/com.youku.v2.HomePageEntry#0 (Max, weight 1.00)09-13 02:26:05.976 590 590 V RefreshRateConfigs: 60fps scores 0.0009-13 02:26:05.976 590 590 V RefreshRateConfigs: layers not scored - choose 60fps09-13 02:26:05.976 590 590 V SurfaceFlinger: trying to switch to Scheduler preferred config 1 (60fps)09-13 02:26:05.976 590 590 V SurfaceFlinger: switching to Scheduler preferred config 109-13 02:26:05.976 590 590 V SurfaceFlinger: setDesiredActiveConfig(60fps)09-13 02:26:05.977 590 590 V SurfaceFlinger: performSetActiveConfig changing active config to 1(60fps)09-13 02:26:05.993 590 590 V SurfaceFlinger: performSetActiveConfig changing active config to 1(60fps)09-13 02:26:05.995 590 590 I SurfaceFlinger: operator()(), mtkRenderCntDebug 79, screenshot (com.youku.phone/com.youku.v2.HomePageEntry#0)09-13 02:26:06.102 590 590 I SurfaceFlinger: operator()(), mtkRenderCntDebug 80, screenshot (com.youku.phone/com.youku.v2.HomePageEntry#0)

现在onDesiredDisplayModeSpecsChangedInternal():通过getDesiredDisplayModesSpecs()方法,获得设置的desiredDisplayModeSpecs(里面有primaryRefreshRate和appRequestRefreshRate的最大最小值).调用setDesiredDisplayModeSpecsLocked():最后调用设置到native层的policy.

SurfacFlinger中的RefreshRate和Policy类定义:RefreshRate:主要成员为fps记录的帧率和ConfigId对应的硬件刷新率 id,并定义了一个inPolicy方法判断该刷新率是否在一定范围内Policy:主要有primaryRange和appRequestRange;

LayerVoteType:用于Layer投票算法决定刷新率的

setDesiredDisplayConfigSpecsInternal函数,通过上面传递进来的新policy,调用setOverridePolicy(policy)更新了mOverridePolicy也就是当前的currentPolicy

getCurrentPolicy获取setDisplayManagerPolicy(policy)更新的mDisplayManagerPolicy赋值给currentPolicy,此policy用于后面getPreferredConfigId函数计算调用calculateRefreshRateConfigIndexType计算获取正确的刷新率进行范围限制,主要是primaryRange限制.

setDesiredDisplayConfigSpecsInternal节选:

adb shell settings put system min_refresh_rate 60 //改变的是primaryRangeadb shell settings put system peak_refresh_rate 120//改变的是appRequestRange09-10 02:22:34.699 593 593 V RefreshRateConfigs: constructAvailableRefreshRates: default 0 group -1 primaryRange=[60.00 60.00] appRequestRange=[0.00 120.00]09-10 02:22:34.699 593 593 V RefreshRateConfigs: getSortedRefreshRateList: config 0 added to list policy09-10 02:22:34.699 593 593 V RefreshRateConfigs: primary refresh rates: 60fps09-10 02:22:34.700 593 593 V RefreshRateConfigs: getSortedRefreshRateList: config 2 added to list policy09-10 02:22:34.700 593 593 V RefreshRateConfigs: getSortedRefreshRateList: config 1 added to list policy09-10 02:22:34.700 593 593 V RefreshRateConfigs: getSortedRefreshRateList: config 0 added to list policy09-10 02:22:34.700 593 593 V RefreshRateConfigs: app request refresh rates: 60fps 90fps 120fps09-10 02:22:34.700 593 593 V SurfaceFlinger: Setting desired display config specs: defaultConfig: 0 primaryRange: [60 60] expandedRange: [0 120]

getPreferredConfigId 同样通过calculateRefreshRateConfigIndexType计算出合适的新频率

getPreferredConfigId 调用栈如下:

09-09 12:02:57.170 583 583 V SurfaceFlinger: Setting desired display config specs: defaultConfig: 0 primaryRange: [0 60] expandedRange: [0 60]09-09 12:02:57.264 583 583 D ha ha : #00 pc 0000000000103ed8 /system/lib64/libsurfaceflinger.so (android::Scheduler::getPreferredConfigId()+76)09-09 12:02:57.265 583 583 D ha ha : #01 pc 0000000000127ba4 /system/lib64/libsurfaceflinger.so (android::SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(android::sp<android::DisplayDevice> const&, std::__1::optional<android::scheduler::RefreshRateConfigs::Policy> const&, bool)+1108)09-09 12:02:57.265 583 583 D ha ha : #02 pc 000000000013841c /system/lib64/libsurfaceflinger.so (_ZNSt3__120__packaged_task_funcIZN7android14SurfaceFlinger28setDesiredDisplayConfigSpecsERKNS1_2spINS1_7IBinderEEEiffffE4$_63NS_9allocatorIS8_EEFivEEclEv$ed74649543c784cf7bf71a82a57ab79d+300)09-09 12:02:57.265 583 583 D ha ha : #03 pc 000000000012db5c /system/lib64/libsurfaceflinger.so (std::__1::packaged_task<int ()>::operator()()+88)09-09 12:02:57.265 583 583 D ha ha : #04 pc 0000000000019ae8 /system/lib64/libutils.so (android::Looper::pollInner(int)+372)09-09 12:02:57.265 583 583 D ha ha : #05 pc 000000000001990c /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+112)09-09 12:02:57.265 583 583 D ha ha : #06 pc 00000000000fc7e0 /system/lib64/libsurfaceflinger.so (android::impl::MessageQueue::waitMessage()+84)09-09 12:02:57.266 583 583 D ha ha : #07 pc 000000000010db84 /system/lib64/libsurfaceflinger.so (android::SurfaceFlinger::run()+20)09-09 12:02:57.266 583 583 D ha ha : #08 pc 0000000000002398 /system/bin/surfaceflinger (main+848)09-09 12:02:57.266 583 583 D ha ha : #09 pc 000000000004973c /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+108)09-09 12:02:57.266 583 583 V RefreshRateConfigs: getRefreshRateForContent 0 layers

calculateRefreshRateConfigIndexTypeHwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType( scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals) { ATRACE_CALL();if (consideredSignals) *consideredSignals = {};// If Display Power is not in normal operation we want to be in performance mode. When coming// back to normal mode, a grace period is given with DisplayPowerTimer.if (mDisplayPowerTimer && (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset)) {return mRefreshRateConfigs.getMaxRefreshRateByPolicy().getConfigId(); }const bool touchActive = mTouchTimer && mFeatures.touch == TouchState::Active;const bool idle = mIdleTimer && mFeatures.idleTimer == TimerState::Expired;if (!mUseContentDetectionV2) {// As long as touch is active we want to be in performance mode.if (touchActive) {return mRefreshRateConfigs.getMaxRefreshRateByPolicy().getConfigId(); }// If timer has expired as it means there is no new content on the screen.if (idle) {if (consideredSignals) consideredSignals->idle = true;return mRefreshRateConfigs.getMinRefreshRateByPolicy().getConfigId(); }// If content detection is off we choose performance as we don't know the content fps.if (mFeatures.contentDetectionV1 == ContentDetectionState::Off) {// NOTE: V1 always calls this, but this is not a default behavior for V2.return mRefreshRateConfigs.getMaxRefreshRateByPolicy().getConfigId(); }// Content detection is on, find the appropriate refresh rate with minimal errorreturn mRefreshRateConfigs.getRefreshRateForContent(mFeatures.contentRequirements) .getConfigId(); }return mRefreshRateConfigs .getBestRefreshRate(mFeatures.contentRequirements, {.touch = touchActive, .idle = idle}, consideredSignals) .getConfigId();}

getBestRefreshRate:此函数就是最终计算最佳刷新率的算法函数:算法的核心就是,每一个layer,根据其配置的LayerVoteType,对当前Policy的mAppRequestRefreshRate内的每一个刷新率进行打分,最后取分数最高的刷新率,作为最后的返回的刷新率.const RefreshRate& RefreshRateConfigs::getBestRefreshRate( const std::vector<LayerRequirement>& layers, const GlobalSignals& globalSignals, GlobalSignals* outSignalsConsidered) const { ATRACE_CALL(); ALOGV("getRefreshRateForContent %zu layers", layers.size()); if (outSignalsConsidered) *outSignalsConsidered = {}; const auto setTouchConsidered = [&] { if (outSignalsConsidered) { outSignalsConsidered->touch = true; } }; const auto setIdleConsidered = [&] { if (outSignalsConsidered) { outSignalsConsidered->idle = true; } }; std::lock_guard lock(mLock); int noVoteLayers = 0; int minVoteLayers = 0; int maxVoteLayers = 0; int explicitDefaultVoteLayers = 0; int explicitExactOrMultipleVoteLayers = 0; float maxExplicitWeight = 0; for (const auto& layer : layers) { if (layer.vote == LayerVoteType::NoVote) { noVoteLayers++; } else if (layer.vote == LayerVoteType::Min) { minVoteLayers++; } else if (layer.vote == LayerVoteType::Max) { maxVoteLayers++; } else if (layer.vote == LayerVoteType::ExplicitDefault) { explicitDefaultVoteLayers++; maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); } else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple) { explicitExactOrMultipleVoteLayers++; maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); } } const bool hasExplicitVoteLayers = explicitDefaultVoteLayers > 0 || explicitExactOrMultipleVoteLayers > 0; // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've // selected a refresh rate to see if we should apply touch boost. if (globalSignals.touch && !hasExplicitVoteLayers) { ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str()); setTouchConsidered(); return getMaxRefreshRateByPolicyLocked(); } // If the primary range consists of a single refresh rate then we can only // move out the of range if layers explicitly request a different refresh // rate. const Policy* policy = getCurrentPolicyLocked(); const bool primaryRangeIsSingleRate = policy->primaryRange.min == policy->primaryRange.max; if (!globalSignals.touch && globalSignals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) { ALOGV("Idle - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str()); setIdleConsidered(); return getMinRefreshRateByPolicyLocked(); } if (layers.empty() || noVoteLayers == layers.size()) { return getMaxRefreshRateByPolicyLocked(); } // Only if all layers want Min we should return Min if (noVoteLayers + minVoteLayers == layers.size()) { ALOGV("all layers Min - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str()); return getMinRefreshRateByPolicyLocked(); } // Find the best refresh rate based on score std::vector<std::pair<const RefreshRate*, float>> scores; scores.reserve(mAppRequestRefreshRates.size()); for (const auto refreshRate : mAppRequestRefreshRates) { scores.emplace_back(refreshRate, 0.0f); } for (const auto& layer : layers) { ALOGV("Calculating score for %s (%s, weight %.2f)", layer.name.c_str(), layerVoteTypeString(layer.vote).c_str(), layer.weight); if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min) { continue; } auto weight = layer.weight; for (auto i = 0u; i < scores.size(); i++) { bool inPrimaryRange = scores[i].first->inPolicy(policy->primaryRange.min, policy->primaryRange.max); if ((primaryRangeIsSingleRate || !inPrimaryRange) && !(layer.focused && layer.vote == LayerVoteType::ExplicitDefault)) { // Only focused layers with ExplicitDefault frame rate settings are allowed to score // refresh rates outside the primary range. continue; } // If the layer wants Max, give higher score to the higher refresh rate if (layer.vote == LayerVoteType::Max) { const auto ratio = scores[i].first->fps / scores.back().first->fps; // use ratio^2 to get a lower score the more we get further from peak const auto layerScore = ratio * ratio; ALOGV("%s (Max, weight %.2f) gives %s score of %.2f", layer.name.c_str(), weight, scores[i].first->name.c_str(), layerScore); scores[i].second += weight * layerScore; continue; } const auto displayPeriod = scores[i].first->hwcConfig->getVsyncPeriod(); const auto layerPeriod = round<nsecs_t>(1e9f / layer.desiredRefreshRate); if (layer.vote == LayerVoteType::ExplicitDefault) { const auto layerScore = [&]() { // Find the actual rate the layer will render, assuming // that layerPeriod is the minimal time to render a frame auto actualLayerPeriod = displayPeriod; int multiplier = 1; while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) { multiplier++; actualLayerPeriod = displayPeriod * multiplier; } return std::min(1.0f, static_cast<float>(layerPeriod) / static_cast<float>(actualLayerPeriod)); }(); ALOGV("%s (ExplicitDefault, weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(), weight, 1e9f / layerPeriod, scores[i].first->name.c_str(), layerScore); scores[i].second += weight * layerScore; continue; } if (layer.vote == LayerVoteType::ExplicitExactOrMultiple || layer.vote == LayerVoteType::Heuristic) { const auto layerScore = [&] { // Calculate how many display vsyncs we need to present a single frame for this // layer const auto [displayFramesQuot, displayFramesRem] = getDisplayFrames(layerPeriod, displayPeriod); static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1 if (displayFramesRem == 0) { // Layer desired refresh rate matches the display rate. return 1.0f; } if (displayFramesQuot == 0) { // Layer desired refresh rate is higher the display rate. return (static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod)) * (1.0f / (MAX_FRAMES_TO_FIT + 1)); } // Layer desired refresh rate is lower the display rate. Check how well it fits // the cadence auto diff = std::abs(displayFramesRem - (displayPeriod - displayFramesRem)); int iter = 2; while (diff > MARGIN_FOR_PERIOD_CALCULATION && iter < MAX_FRAMES_TO_FIT) { diff = diff - (displayPeriod - diff); iter++; } return 1.0f / iter; }(); ALOGV("%s (%s, weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(), layerVoteTypeString(layer.vote).c_str(), weight, 1e9f / layerPeriod, scores[i].first->name.c_str(), layerScore); scores[i].second += weight * layerScore; continue; } } } // Now that we scored all the refresh rates we need to pick the one that got the highest score. // In case of a tie we will pick the higher refresh rate if any of the layers wanted Max, // or the lower otherwise. const RefreshRate* bestRefreshRate = maxVoteLayers > 0 ? getBestRefreshRate(scores.rbegin(), scores.rend()) : getBestRefreshRate(scores.begin(), scores.end()); if (primaryRangeIsSingleRate) { // If we never scored any layers, then choose the rate from the primary // range instead of picking a random score from the app range. if (std::all_of(scores.begin(), scores.end(), [](std::pair<const RefreshRate*, float> p) { return p.second == 0; })) { ALOGV("layers not scored - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str()); return getMaxRefreshRateByPolicyLocked(); } else { return *bestRefreshRate; } } // Consider the touch event if there are no ExplicitDefault layers. ExplicitDefault are mostly // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit // vote we should not change it if we get a touch event. Only apply touch boost if it will // actually increase the refresh rate over the normal selection. const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked(); if (globalSignals.touch && explicitDefaultVoteLayers == 0 && bestRefreshRate->fps < touchRefreshRate.fps) { setTouchConsidered(); ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str()); return touchRefreshRate; } return *bestRefreshRate;}参考文献:在 Android 上进行高刷新率渲染 - Android开发者 - OSCHINA - 中文开源技术交流社区

作者:Carlis

来源-微信公众号:酷派技术团队

出处:https://mp.weixin.qq.com/s/CEBxHReeZL6M6mIuDVnY2A

0 阅读:0

以云看科技

简介:感谢大家的关注