SwallowJoe的博客

Be a real go-getter,
NEVER SETTLE!

0%

App申请帧率(3)--SF计算最佳帧率

以下分析基于Android R.

简述

上一章我们分析了App是如何通过更改一个小小的WindowManager的LayoutParam的属性,来影响Framework决策帧率变化的。

接来下我们详细看看SurfaceFlinger是如何根据Framework传入的帧率参数选择合适帧率的。

一. SurfaceFlinger接受帧率变化

接上一章,从 SurfaceFlinger::setAllowedDisplayConfigs 开始. 但是Android R上入口函数些许变化:

由SurfaceControl.setAllowedDisplayConfigs(getDisplayTokenLocked(), allowedPhysIndexes)

=》SurfaceControl.setDesiredDisplayConfigSpecs(displayToken, configSpecs);

这里的configSpecs是DesiredDisplayConfigSpecs类型

1.1 SurfaceControl.setDesiredDisplayConfigSpecs

1
2
3
4
5
6
7
8
public static boolean setDesiredDisplayConfigSpecs(IBinder displayToken,
SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}

return nativeSetDesiredDisplayConfigSpecs(displayToken, desiredDisplayConfigSpecs);
}

1.1.1 android_view_SurfaceControl.nativeSetDesiredDisplayConfigSpecs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
static jboolean nativeSetDesiredDisplayConfigSpecs(JNIEnv* env, jclass clazz, jobject tokenObj,
jobject desiredDisplayConfigSpecs) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == nullptr) return JNI_FALSE;

jint defaultConfig = env->GetIntField(desiredDisplayConfigSpecs,
gDesiredDisplayConfigSpecsClassInfo.defaultConfig);
jfloat primaryRefreshRateMin =
env->GetFloatField(desiredDisplayConfigSpecs,
gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMin);
jfloat primaryRefreshRateMax =
env->GetFloatField(desiredDisplayConfigSpecs,
gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMax);
jfloat appRequestRefreshRateMin =
env->GetFloatField(desiredDisplayConfigSpecs,
gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMin);
jfloat appRequestRefreshRateMax =
env->GetFloatField(desiredDisplayConfigSpecs,
gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMax);

size_t result = SurfaceComposerClient::setDesiredDisplayConfigSpecs(token, defaultConfig,
primaryRefreshRateMin,
primaryRefreshRateMax,
appRequestRefreshRateMin,
appRequestRefreshRateMax);
return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}

1.1.2 SurfaceComposerClient.setDesiredDisplayConfigSpecs

1
2
3
4
5
6
7
8
9
10
11
12
status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t defaultConfig,
float primaryRefreshRateMin,
float primaryRefreshRateMax,
float appRequestRefreshRateMin,
float appRequestRefreshRateMax) {
// 转到SurfaceFlinger
return ComposerService::getComposerService()
->setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin,
primaryRefreshRateMax, appRequestRefreshRateMin,
appRequestRefreshRateMax);
}

1.2 SurfaceFlinger.setDesiredDisplayConfigSpecs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t defaultConfig,
float primaryRefreshRateMin,
float primaryRefreshRateMax,
float appRequestRefreshRateMin,
float appRequestRefreshRateMax) {
ATRACE_CALL();

if (!displayToken) {
return BAD_VALUE;
}

// Lambda表达式
auto future = schedule([=]() -> status_t {
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
ALOGE("Attempt to set desired display configs for invalid display token %p",
displayToken.get());
return NAME_NOT_FOUND;
} else if (display->isVirtual()) {
ALOGW("Attempt to set desired display configs for virtual display");
return INVALID_OPERATION;
} else {
using Policy = scheduler::RefreshRateConfigs::Policy;
// 初始化policy
const Policy policy{HwcConfigIndexType(defaultConfig),
{primaryRefreshRateMin, primaryRefreshRateMax},
{appRequestRefreshRateMin, appRequestRefreshRateMax}};
constexpr bool kOverridePolicy = false;

return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
}
});

return future.get();
}

1.2.1 SurfaceFlinger.schedule

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
template <typename F, typename T>
inline std::future<T> SurfaceFlinger::schedule(F&& f) {
auto [task, future] = makeTask(std::move(f));
mEventQueue->postMessage(std::move(task));
return std::move(future);
}

// MessageQueue.h
template <typename F>
inline auto makeTask(F&& f) {
sp<Task<F>> task = new Task<F>(std::move(f));
return std::make_pair(task, task->mTask.get_future());
}
// MessageQueue.h
template <typename F>
class Task : public MessageHandler {
template <typename G>
friend auto makeTask(G&&);

explicit Task(F&& f) : mTask(std::move(f)) {}

void handleMessage(const Message&) override { mTask(); }

using T = std::invoke_result_t<F>;
std::packaged_task<T()> mTask;
};

1.3 SurfaceFlinger.setDesiredDisplayConfigSpecsInternal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(
const sp<DisplayDevice>& display,
const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) {
Mutex::Autolock lock(mStateLock);
......
// overridePolicy 一般都是false
status_t setPolicyResult = overridePolicy
? mRefreshRateConfigs->setOverridePolicy(policy)
// 1.3.1 更改当前帧率策略
: mRefreshRateConfigs->setDisplayManagerPolicy(*policy);
if (setPolicyResult < 0) {
return BAD_VALUE;
}
if (setPolicyResult == scheduler::RefreshRateConfigs::CURRENT_POLICY_UNCHANGED) {
return NO_ERROR;
}
scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();

ALOGV("Setting desired display config specs: defaultConfig: %d primaryRange: [%.0f %.0f]"
" expandedRange: [%.0f %.0f]",
currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min,
currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min,
currentPolicy.appRequestRange.max);

// TODO(b/140204874): Leave the event in until we do proper testing with all apps that might
// be depending in this callback.
const nsecs_t vsyncPeriod =
mRefreshRateConfigs->getRefreshRateFromConfigId(display->getActiveConfig())
.getVsyncPeriod();
mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, display->getId()->value,
display->getActiveConfig(), vsyncPeriod);
toggleKernelIdleTimer();

// 1.3.3 获取configId
auto configId = mScheduler->getPreferredConfigId();
// configId是std::optional<HwcConfigIndexType>类型的,这里判断是否存在值,一般存在
// 根据HwcConfigIndexType获取实际的 RefreshRate 参数
auto& preferredRefreshRate = configId
? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId)
// NOTE: Choose the default config ID, if Scheduler doesn't have one in mind.
: mRefreshRateConfigs->getRefreshRateFromConfigId(currentPolicy.defaultConfig);
ALOGV("trying to switch to Scheduler preferred config %d (%s)",
preferredRefreshRate.getConfigId().value(), preferredRefreshRate.getName().c_str());

// 判断RefreshRate是否合法
if (isDisplayConfigAllowed(preferredRefreshRate.getConfigId())) {
ALOGV("switching to Scheduler preferred config %d",
preferredRefreshRate.getConfigId().value());
// 1.4 设置帧率
setDesiredActiveConfig(
{preferredRefreshRate.getConfigId(), Scheduler::ConfigEvent::Changed});
} else {
LOG_ALWAYS_FATAL("Desired config not allowed: %d",
preferredRefreshRate.getConfigId().value());
}

return NO_ERROR;
}

1.3.1 RefreshRateConfigs.setDisplayManagerPolicy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
std::lock_guard lock(mLock);
if (!isPolicyValid(policy)) {
return BAD_VALUE;
}
// 获取当前策略,如果mOverridePolicy是false,也就是没有覆写
// 就是用的mDisplayManagerPolicy
Policy previousPolicy = *getCurrentPolicyLocked();
mDisplayManagerPolicy = policy;
if (*getCurrentPolicyLocked() == previousPolicy) {
return CURRENT_POLICY_UNCHANGED;
}
// 1.3.2 根据策略构建最终刷新率
constructAvailableRefreshRates();
return NO_ERROR;
}

1.3.2 RefreshRateConfigs.constructAvailableRefreshRates

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
void RefreshRateConfigs::constructAvailableRefreshRates() {
// Filter configs based on current policy and sort based on vsync period
const Policy* policy = getCurrentPolicyLocked();
const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig)->hwcConfig;
ALOGV("constructAvailableRefreshRates: default %d group %d primaryRange=[%.2f %.2f]"
" appRequestRange=[%.2f %.2f]",
policy->defaultConfig.value(), defaultConfig->getConfigGroup(), policy->primaryRange.min,
policy->primaryRange.max, policy->appRequestRange.min, policy->appRequestRange.max);

// lambuda A
auto filterRefreshRates = [&](float min, float max, const char* listName,
std::vector<const RefreshRate*>* outRefreshRates) {
// lambuda B
getSortedRefreshRateList(
[&](const RefreshRate& refreshRate) REQUIRES(mLock) {
const auto& hwcConfig = refreshRate.hwcConfig;

return hwcConfig->getHeight() == defaultConfig->getHeight() &&
hwcConfig->getWidth() == defaultConfig->getWidth() &&
hwcConfig->getDpiX() == defaultConfig->getDpiX() &&
hwcConfig->getDpiY() == defaultConfig->getDpiY() &&
(policy->allowGroupSwitching ||
hwcConfig->getConfigGroup() == defaultConfig->getConfigGroup()) &&
refreshRate.inPolicy(min, max);
},
outRefreshRates);

LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(),
"No matching configs for %s range: min=%.0f max=%.0f", listName, min,
max);
auto stringifyRefreshRates = [&]() -> std::string {
std::string str;
for (auto refreshRate : *outRefreshRates) {
base::StringAppendF(&str, "%s ", refreshRate->name.c_str());
}
return str;
};
ALOGV("%s refresh rates: %s", listName, stringifyRefreshRates().c_str());
};

filterRefreshRates(policy->primaryRange.min, policy->primaryRange.max, "primary",
&mPrimaryRefreshRates);
filterRefreshRates(policy->appRequestRange.min, policy->appRequestRange.max, "app request",
&mAppRequestRefreshRates);
}

void RefreshRateConfigs::getSortedRefreshRateList(
const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate,
std::vector<const RefreshRate*>* outRefreshRates) {
outRefreshRates->clear();
outRefreshRates->reserve(mRefreshRates.size());
// 遍历所有可能的RefreshRate
for (const auto& [type, refreshRate] : mRefreshRates) {
// 调用上面的lambuda B方法, 其实就是条件判断
if (shouldAddRefreshRate(*refreshRate)) {
ALOGV("getSortedRefreshRateList: config %d added to list policy",
refreshRate->configId.value());
outRefreshRates->push_back(refreshRate.get());
}
}

// 按照帧率大小排序,VsyncPeriod越大,Fps越小。
// 这里就是按照Fps升序排序了
std::sort(outRefreshRates->begin(), outRefreshRates->end(),
[](const auto refreshRate1, const auto refreshRate2) {
if (refreshRate1->hwcConfig->getVsyncPeriod() !=
refreshRate2->hwcConfig->getVsyncPeriod()) {
return refreshRate1->hwcConfig->getVsyncPeriod() >
refreshRate2->hwcConfig->getVsyncPeriod();
} else {
return refreshRate1->hwcConfig->getConfigGroup() >
refreshRate2->hwcConfig->getConfigGroup();
}
});
}

这里吐槽一下,写的很丑。直接说明,在 mRefreshRates中寻找符合要求的configId(modeId)放入对应的集合中。

这里说的符合要求是指:

  1. 宽高与所设置的Policy中的defaultConfig的宽高一致
  2. 其帧率在所设置的Policy的最小和最大帧率之中

最终将结果保存在变量:mPrimaryRefreshRates以及mAppRequestRefreshRates中。

1.3.3 Scheduler.getPreferredConfigId

1
2
3
4
5
6
7
8
9
10
11
std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() {
std::lock_guard<std::mutex> lock(mFeatureStateLock);
// Make sure that the default config ID is first updated, before returned.
// mFeatures 是一个结构体
if (mFeatures.configId.has_value()) {
// configId是一个 std:optional的变量
// 计算当前刷新率的configId
mFeatures.configId = calculateRefreshRateConfigIndexType();
}
return mFeatures.configId;
}

这个地方原以为mFeatures.configId一般是存在value的,其实并不是。

1.3.4 Scheduler.calculateRefreshRateConfigIndexType

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// consideredSignals 的默认参数是nullptr的
HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType(
scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals) {
ATRACE_CALL();
// ......
const bool touchActive = mTouchTimer && mFeatures.touch == TouchState::Active;
const bool idle = mIdleTimer && mFeatures.idleTimer == TimerState::Expired;

// ......
// 1.3.5 获取最佳ConfigId, 根据framework传来的帧率范围, 以及当下Layer投票产生
return mRefreshRateConfigs
.getBestRefreshRate(mFeatures.contentRequirements, {.touch = touchActive, .idle = idle},
consideredSignals)
.getConfigId();
}

1.3.5 RefreshRateConfigs.getBestRefreshRate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
const std::vector<LayerRequirement>& layers, const GlobalSignals& globalSignals,
GlobalSignals* outSignalsConsidered) const {
ATRACE_CALL();
ALOGV("getRefreshRateForContent %zu layers", layers.size());

// 注意传入的outSignalsConsidered是nullptr的
if (outSignalsConsidered) *outSignalsConsidered = {};
const auto setTouchConsidered = [&] {
if (outSignalsConsidered) {
outSignalsConsidered->touch = true;
}
};

const auto setIdleConsidered = [&] {
if (outSignalsConsidered) {
outSignalsConsidered->idle = true;
}
};

std::lock_guard lock(mLock);
// 开始投票
// 首先计算所有不同LayerVoteType的数量
// 这里的Type稍后介绍
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;

// $1. 如果没有显式Layer, 考虑触摸事件, 如果存在触摸事件, 选择最大帧率
if (globalSignals.touch && !hasExplicitVoteLayers) {
ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str());
setTouchConsidered();
return getMaxRefreshRateByPolicyLocked();
}

// 如果刷新率范围由单个刷新率组成,那么只有当层显式请求不同的刷新率时,才能选择超出范围
const Policy* policy = getCurrentPolicyLocked();
const bool primaryRangeIsSingleRate = policy->primaryRange.min == policy->primaryRange.max;

// $2. 没有touch事件,屏幕处于idle状态, 刷新率存在一定范围或者不存在显示请求刷新率的Layer时
// 选择最小帧率
if (!globalSignals.touch && globalSignals.idle &&
!(primaryRangeIsSingleRate && hasExplicitVoteLayers)) {
ALOGV("Idle - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str());
setIdleConsidered();
return getMinRefreshRateByPolicyLocked();
}

// $3. 没有Layer或者所有Layer都没有投票(NoVote)时, 选择最大帧率???
if (layers.empty() || noVoteLayers == layers.size()) {
return getMaxRefreshRateByPolicyLocked();
}

// $4. 存在Layer且所有Layer要么不投票,要么请求最小帧率时,选择最小帧率
if (noVoteLayers + minVoteLayers == layers.size()) {
ALOGV("all layers Min - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str());
return getMinRefreshRateByPolicyLocked();
}

// $5. 计算找到最佳刷新率
std::vector<std::pair<const RefreshRate*, float>> scores;
scores.reserve(mAppRequestRefreshRates.size());

for (const auto refreshRate : mAppRequestRefreshRates) {
scores.emplace_back(refreshRate, 0.0f);
}

// 遍历所有Layer
for (const auto& layer : layers) {
ALOGV("Calculating score for %s (%s, weight %.2f)", layer.name.c_str(),
layerVoteTypeString(layer.vote).c_str(), layer.weight);
// 忽略不投票或者投票选择最小帧率的Layer
if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min) {
continue;
}

auto weight = layer.weight;
// 注意这里还有一层循环,分别计算每个AppRequestRefreshRate的得分
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 ||
layer.vote == LayerVoteType::ExplicitExactOrMultiple))) {
// $$5.1 只有具有显式帧速率设置的聚焦层才允许对主范围之外的刷新率进行评分
// 换句话说,只有ExplicitDefault或者ExplicitExactOrMultiple类型的Layer,且该Layer是有焦点的
// 才允许投票超出刷新率请求范围的帧率
continue;
}

// $$5.2 如果图层想要最大值,给更高的刷新率评分
if (layer.vote == LayerVoteType::Max) {
// 用当前layer(app)请求的帧率除以最后一个layer(app)请求的帧率
// 注意到mAppRequestRefreshRates中fps是按照升序排序的,最后一个是最大的
// 所以这里就是用 当前请求的帧率除以最大的请求帧率得到一个 (0, 1] 的比值
const auto ratio = scores[i].first->fps / scores.back().first->fps;
// 使用比值的平方得到一个较低的分数 ==> 为啥?
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);
// 将比值的平方乘上权重系数,作为该layer的分数
scores[i].second += weight * layerScore;
continue;
}

// 屏幕刷新率
const auto displayPeriod = scores[i].first->hwcConfig->getVsyncPeriod();
// Layer所需的刷新率
const auto layerPeriod = round<nsecs_t>(1e9f / layer.desiredRefreshRate);
// $$5.3 如果是ExplicitDefault类型的Layer
if (layer.vote == LayerVoteType::ExplicitDefault) {
const auto layerScore = [&]() {
// 找到Layer将渲染的实际速率,假设layerPeriod是渲染帧的最短时间
auto actualLayerPeriod = displayPeriod;
int multiplier = 1;
// 刷新时长依次翻倍,直到满足该Layer刷新的最低时长,也就是fps大小每次折半
// MARGIN_FOR_PERIOD_CALCULATION = 800us
while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) {
multiplier++;
actualLayerPeriod = displayPeriod * multiplier;
}
// 此时layer分数为 layer所需的时长除以满足刷新要求的最长时长
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);
// layer分数乘上权重作为该layer的最终分数
scores[i].second += weight * layerScore;
continue;
}

// $$5.4 如果是ExplicitExactOrMultiple或者Heuristic类型的Layer
if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
layer.vote == LayerVoteType::Heuristic) {
const auto layerScore = [&] {
// 计算我们需要多少个显示vSync来显示这个层的一个帧
// 其实就是计算 layerPeriod/displayPeriod 得到商和余数
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) {
// 整除的时候,直接返回1?
// 说明layer请求的fps是比display的fps小,得分直接拉满
return 1.0f;
}

if (displayFramesQuot == 0) {
// 当layer请求的fps比display中的fps要大的时候
// 返回layer period除以display period的商的十一分之一
// 比如 layer = 120Hz, display = 90Hz
// 8.33333 1.0
// return = ----------- * ----
// 11.1111 11
// 为啥怎么算呢,这里分数的极限值也就是1/11,最大限度排除这个layer请求的帧率?
return (static_cast<float>(layerPeriod) /
static_cast<float>(displayPeriod)) *
(1.0f / (MAX_FRAMES_TO_FIT + 1));
}

// layer所需的刷新率低于的显示刷新率,但又不是整数倍关系,检查它是否符合节奏
// 计算差值: 用 Pl 表述 layer period,Pd表示display period
// diff = | (Pl mod Pd) * 2 - Pd |
// 这里的意思是在计算多少帧内,display 刷新可以匹配 layer请求的刷新
auto diff = std::abs(displayFramesRem - (displayPeriod - displayFramesRem));
int iter = 2;
while (diff > MARGIN_FOR_PERIOD_CALCULATION && iter < MAX_FRAMES_TO_FIT) {
// 循环计算,总结公式:
// 1. diff0 = 2 * (Pl mod Pd) - Pd, Pl > Pd 且 K ∈ {1,2,3,...,9}
// 2. 当diff0 > 0 时, diff = (Pl mod Pd) * 2^k - Pd * (2^k-1)
// 3. 当diff0 < 0 时, diff = Pd - 2^k * (Pl mode Pd)
diff = diff - (displayPeriod - diff);
iter++;
}

// 得分取值范围是[0.1, 0.5]
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;
}
}
}

// $6 如果存在请求最大帧率的layer就反向遍历
// 找到得分最大的帧率
const RefreshRate* bestRefreshRate = maxVoteLayers > 0
? getBestRefreshRate(scores.rbegin(), scores.rend())
: getBestRefreshRate(scores.begin(), scores.end());

// 显示主刷新率没有范围,只有定值时
if (primaryRangeIsSingleRate) {
// 如果没有layer参与评分,从显示主刷新范围选取最大值
// 否则返回计算得出的最佳刷新率
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;
}
}

// 如果没有explicitDefaultLayers,请考虑touch事件。
// ExplicitDefault主要是交互式的(与ExplicitExactOrMultiple相反),因此如果那些Layer发布了一个显式投票,
// 那么存在touch事件,就不应该更改它。只有在触摸增强会增加刷新率超过正常选择时才应用。
const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked();

// 存在touch事件,不存在ExplicitDefault的Layer且显示主范围刷新率最大值大于计算的刷新率时
// 采用最大刷新率
if (globalSignals.touch && explicitDefaultVoteLayers == 0 &&
bestRefreshRate->fps < touchRefreshRate.fps) {
setTouchConsidered();
ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str());
return touchRefreshRate;
}

return *bestRefreshRate;
}

Emmmm…. 这一言难尽的代码。

总结一下,在上层计算传入两个刷新率范围后,这里主要是根据Layer投票以及一系列判断得到最终所需的刷新率。

说明一下几个概念:

  1. 显示主范围刷新率: DisplayModeDirector中投票算出的包含所有请求帧率的最小范围
  2. layerPeriod: 根据当前layer.desiredRefreshRate计算出一帧的时长
  3. displayPeriod: 当前AppReqeustRefereshRate中HwcConfig计算的一帧时长

整个投票过程简述:

  1. 首先计算所有不同LayerVoteType的数量
  2. 如果没有显式Layer,即ExplicitDefault和ExplicitExactOrMultiple类型,且存在触摸事件, 直接选择主范围刷新率最大帧率
  3. 没有touch事件且屏幕处于idle状态, 刷新率存在一定范围或者不存在显示请求刷新率的Layer时, 选择主范围刷新率最小帧率
  4. 没有Layer或者所有Layer都没有投票(NoVote)时, 选择最大帧率
  5. 存在Layer且所有Layer要么不投票,要么请求最小帧率时,选择最小帧率
  6. 当上述条件都不满足时,遍历所有Layer计算每个AppRequestRefreshRate的得分,找到最佳刷新率, 注意遍历时, 忽略不投票或者投票选择最小帧率的Layer
    1. 遍历所有AppRequestRefreshRate
      1. 只有ExplicitDefault或者ExplicitExactOrMultiple类型的Layer,且该Layer是有焦点的才允许投票超出刷新率请求范围的帧率,否则忽略该Layer
      2. 如果Layer是Max类型
        1. 用当前layer(app)请求的帧率除以最后一个layer(app)请求的帧率,得到的比值的平方乘以权重,计入当前AppRequestRefreshRate的分数
      3. 如果是ExplicitDefault类型的Layer
        1. 找到Layer将渲染的实际速率,首先假设layer.desiredRefreshRate计算的Period是渲染帧的最短时间
        2. 将该AppReqeustRefereshRate中的Display Period刷新时长依次翻倍,直到满足该Layer刷新的最低时长,也就是fps大小每次折半
        3. 此时layer分数为 layer所需的时长除以满足刷新要求的最长时长在乘以权重计入当前AppRequestRefreshRate的分数
      4. 如果是ExplicitExactOrMultiple或者Heuristic类型的Layer
        1. 首先计算需要多少个显示vSync来显示这个层的一个帧,即计算 layerPeriod/displayPeriod 得到商 quot 和余数 rem
        2. 如果是整数倍关系,当前AppRequestRefreshRate的分数直接加上该Layer的权重
        3. 当layer请求的fps比AppReqeustRefereshRate中的实际display的fps要大的时候,得分是layer period除以display period的商的十一分之一乘以layer的权重
        4. layer所需的刷新率低于的显示刷新率,但又不是整数倍关系时,用 Pl 表述 layer period,Pd表示display period
          1. diff0 = 2 * (Pl mod Pd) - Pd, Pl > Pd 且 K ∈ {1,2,3,…,9}
          2. 当diff0 > 0 时, diff = (Pl mod Pd) * 2^k - Pd * (2^k-1)
          3. 当diff0 < 0 时, diff = Pd - 2^k * (Pl mode Pd)
          4. 当diff小于800时(差值小于800us), 或者k>9结束, 得分是当前Layer的权重乘以1/(2K)
  7. 如果存在请求最大帧率的layer就反向遍历,找到得分最大的帧率 bestRefreshRate
  8. 如果显示主刷新率没有范围,比如最小值和最大值都是120Hz时
    1. 如果没有layer参与评分,从显示主刷新范围选取最大值
    2. 否则返回计算得出的最佳刷新率
  9. 如果存在touch事件, 不存在ExplicitDefault的Layer且显示主范围刷新率最大值大于计算的刷新率时, 采用最大刷新率
  10. 以上条件均不满足时,返回计算的bestRefreshRate

好了,本次分析到此为止,接下来就是继续看SurfaceFlinger如何通知HWC硬件切换帧率了。

欢迎关注我的其它发布渠道