Make shouldBeSeamless an enum
We change theboolean shouldBeSemaless to an enum with
three values. This introduces a third value "Default" which
indicates that the layer doesn't have a preference for
seamlessness. This is the default value for Surfaces which
haven't called setFrameRate, or have called setFrameRate(0).
Bug: 161776961
Test: presubmit
Change-Id: I157e332e82e95badc928d6a8135e657cd6984db4
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 28af930..359ee26 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -129,8 +129,7 @@
RefreshRateConfigs::LayerRequirement{.name = layer->getName(),
.vote = voteType,
.desiredRefreshRate = frameRate.rate,
- .shouldBeSeamless =
- frameRate.shouldBeSeamless,
+ .seamlessness = frameRate.seamlessness,
.weight = 1.0f,
.focused = layerFocused});
} else if (recent) {
@@ -139,7 +138,8 @@
.vote = LayerVoteType::Heuristic,
.desiredRefreshRate =
info->getRefreshRate(now),
- .shouldBeSeamless = true,
+ .seamlessness =
+ Seamlessness::OnlySeamless,
.weight = 1.0f,
.focused = layerFocused});
}
diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
index a63ccc1..e919d1b 100644
--- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
@@ -144,8 +144,8 @@
const float layerArea = transformed.getWidth() * transformed.getHeight();
float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f;
- summary.push_back({strong->getName(), vote.type, vote.fps, vote.shouldBeSeamless, weight,
- layerFocused});
+ summary.push_back(
+ {strong->getName(), vote.type, vote.fps, vote.seamlessness, weight, layerFocused});
if (CC_UNLIKELY(mTraceEnabled)) {
trace(layer, *info, vote.type, static_cast<int>(std::round(vote.fps)));
@@ -179,7 +179,7 @@
if (frameRate.rate > 0 || voteType == LayerVoteType::NoVote) {
const auto type = layer->isVisible() ? voteType : LayerVoteType::NoVote;
- info->setLayerVote({type, frameRate.rate, frameRate.shouldBeSeamless});
+ info->setLayerVote({type, frameRate.rate, frameRate.seamlessness});
} else {
info->resetLayerVote();
}
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h
index 2305bc3..f94f4ab 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.h
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h
@@ -23,6 +23,7 @@
#include "LayerHistory.h"
#include "RefreshRateConfigs.h"
+#include "Scheduler/Seamlessness.h"
#include "SchedulerUtils.h"
namespace android {
@@ -60,7 +61,7 @@
struct LayerVote {
LayerHistory::LayerVoteType type = LayerHistory::LayerVoteType::Heuristic;
float fps = 0.0f;
- bool shouldBeSeamless = true;
+ Seamlessness seamlessness = Seamlessness::Default;
};
static void setTraceEnabled(bool enabled) { sTraceEnabled = enabled; }
@@ -91,7 +92,7 @@
void setDefaultLayerVote(LayerHistory::LayerVoteType type) { mDefaultVote = type; }
// Resets the layer vote to its default.
- void resetLayerVote() { mLayerVote = {mDefaultVote, 0.0f, true}; }
+ void resetLayerVote() { mLayerVote = {mDefaultVote, 0.0f, Seamlessness::Default}; }
LayerVote getRefreshRateVote(nsecs_t now);
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index b872d7a..4ebab3e 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -27,6 +27,14 @@
#define LOG_TAG "RefreshRateConfigs"
namespace android::scheduler {
+namespace {
+std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) {
+ return base::StringPrintf("%s (type=%s, weight=%.2f seamlessness=%s) %.2fHz",
+ layer.name.c_str(),
+ RefreshRateConfigs::layerVoteTypeString(layer.vote).c_str(), weight,
+ toString(layer.seamlessness).c_str(), layer.desiredRefreshRate);
+}
+} // namespace
using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType;
using RefreshRate = RefreshRateConfigs::RefreshRate;
@@ -170,7 +178,7 @@
maxExplicitWeight = std::max(maxExplicitWeight, layer.weight);
}
- if (!layer.shouldBeSeamless) {
+ if (layer.seamlessness == Seamlessness::SeamedAndSeamless) {
seamedLayers++;
}
}
@@ -229,27 +237,38 @@
auto weight = layer.weight;
for (auto i = 0u; i < scores.size(); i++) {
- // If there are no layers with shouldBeSeamless=false and the current
- // config group is different from the default one, this means a layer with
- // shouldBeSeamless=false has just disappeared and we should switch back to
- // the default config group.
- const bool isSeamlessSwitch = seamedLayers > 0
- ? scores[i].first->getConfigGroup() == mCurrentRefreshRate->getConfigGroup()
- : scores[i].first->getConfigGroup() == defaultConfig->getConfigGroup();
+ const bool isSeamlessSwitch =
+ scores[i].first->getConfigGroup() == mCurrentRefreshRate->getConfigGroup();
- if (layer.shouldBeSeamless && !isSeamlessSwitch) {
- ALOGV("%s (weight %.2f) ignores %s (group=%d) to avoid non-seamless switch."
- "Current config = %s",
- layer.name.c_str(), weight, scores[i].first->name.c_str(),
- scores[i].first->getConfigGroup(), mCurrentRefreshRate->toString().c_str());
+ if (layer.seamlessness == Seamlessness::OnlySeamless && !isSeamlessSwitch) {
+ ALOGV("%s ignores %s to avoid non-seamless switch. Current config = %s",
+ formatLayerInfo(layer, weight).c_str(), scores[i].first->toString().c_str(),
+ mCurrentRefreshRate->toString().c_str());
continue;
}
- if (!layer.shouldBeSeamless && !isSeamlessSwitch && !layer.focused) {
- ALOGV("%s (weight %.2f) ignores %s (group=%d) because it's not focused"
- " and the switch is going to be seamed. Current config = %s",
- layer.name.c_str(), weight, scores[i].first->name.c_str(),
- scores[i].first->getConfigGroup(), mCurrentRefreshRate->toString().c_str());
+ if (layer.seamlessness == Seamlessness::SeamedAndSeamless && !isSeamlessSwitch &&
+ !layer.focused) {
+ ALOGV("%s ignores %s because it's not focused and the switch is going to be seamed."
+ " Current config = %s",
+ formatLayerInfo(layer, weight).c_str(), scores[i].first->toString().c_str(),
+ mCurrentRefreshRate->toString().c_str());
+ continue;
+ }
+
+ // Layers with default seamlessness vote for the current config group if
+ // there are layers with seamlessness=SeamedAndSeamless and for the default
+ // config group otherwise. In second case, if the current config group is different
+ // from the default, this means a layer with seamlessness=SeamedAndSeamless has just
+ // disappeared.
+ const bool isInPolicyForDefault = seamedLayers > 0
+ ? scores[i].first->getConfigGroup() == mCurrentRefreshRate->getConfigGroup()
+ : scores[i].first->getConfigGroup() == defaultConfig->getConfigGroup();
+
+ if (layer.seamlessness == Seamlessness::Default && !isInPolicyForDefault &&
+ !layer.focused) {
+ ALOGV("%s ignores %s. Current config = %s", formatLayerInfo(layer, weight).c_str(),
+ scores[i].first->toString().c_str(), mCurrentRefreshRate->toString().c_str());
continue;
}
@@ -267,7 +286,7 @@
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,
+ ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
scores[i].first->name.c_str(), layerScore);
scores[i].second += weight * layerScore;
continue;
@@ -290,9 +309,8 @@
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);
+ ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
+ scores[i].first->name.c_str(), layerScore);
scores[i].second += weight * layerScore;
continue;
}
@@ -332,8 +350,7 @@
// Slightly prefer seamless switches.
constexpr float kSeamedSwitchPenalty = 0.95f;
const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
- ALOGV("%s (%s, weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(),
- layerVoteTypeString(layer.vote).c_str(), weight, 1e9f / layerPeriod,
+ ALOGV("%s gives %s score of %.2f", formatLayerInfo(layer, weight).c_str(),
scores[i].first->name.c_str(), layerScore);
scores[i].second += weight * layerScore * seamlessness;
continue;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 3159352..2ef8f0c 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -26,6 +26,7 @@
#include "DisplayHardware/HWComposer.h"
#include "HwcStrongTypes.h"
#include "Scheduler/SchedulerUtils.h"
+#include "Scheduler/Seamlessness.h"
#include "Scheduler/StrongTyping.h"
namespace android::scheduler {
@@ -219,7 +220,7 @@
// Layer's desired refresh rate, if applicable.
float desiredRefreshRate = 0.0f;
// If a seamless mode switch is required.
- bool shouldBeSeamless = true;
+ Seamlessness seamlessness = Seamlessness::Default;
// Layer's weight in the range of [0, 1]. The higher the weight the more impact this layer
// would have on choosing the refresh rate.
float weight = 0.0f;
diff --git a/services/surfaceflinger/Scheduler/Seamlessness.h b/services/surfaceflinger/Scheduler/Seamlessness.h
new file mode 100644
index 0000000..3e42a4d
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/Seamlessness.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstring>
+#include <ostream>
+
+namespace android {
+namespace scheduler {
+
+// The seamlessness requirement of a Layer.
+enum class Seamlessness {
+ // Indicates a requirement for a seamless mode switch.
+ OnlySeamless,
+ // Indicates that both seamless and seamed mode switches are allowed.
+ SeamedAndSeamless,
+ // Indicates no preference for seamlessness. For such layers the system will
+ // prefer seamless switches, but also non-seamless switches to the group of the
+ // default config are allowed.
+ Default
+};
+
+inline std::string toString(Seamlessness seamlessness) {
+ switch (seamlessness) {
+ case Seamlessness::OnlySeamless:
+ return "OnlySeamless";
+ case Seamlessness::SeamedAndSeamless:
+ return "SeamedAndSeamless";
+ case Seamlessness::Default:
+ return "Default";
+ }
+}
+
+// Used by gtest
+inline std::ostream& operator<<(std::ostream& os, Seamlessness val) {
+ return os << toString(val);
+}
+
+} // namespace scheduler
+} // namespace android