Merge "Split refresh rate range into two ranges" into rvc-dev
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 6fd53cf..2a27a9a 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -931,8 +931,11 @@
}
virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig, float minRefreshRate,
- float maxRefreshRate) {
+ int32_t defaultConfig,
+ float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
if (result != NO_ERROR) {
@@ -949,14 +952,26 @@
ALOGE("setDesiredDisplayConfigSpecs failed to write defaultConfig: %d", result);
return result;
}
- result = data.writeFloat(minRefreshRate);
+ result = data.writeFloat(primaryRefreshRateMin);
if (result != NO_ERROR) {
- ALOGE("setDesiredDisplayConfigSpecs failed to write minRefreshRate: %d", result);
+ ALOGE("setDesiredDisplayConfigSpecs failed to write primaryRefreshRateMin: %d", result);
return result;
}
- result = data.writeFloat(maxRefreshRate);
+ result = data.writeFloat(primaryRefreshRateMax);
if (result != NO_ERROR) {
- ALOGE("setDesiredDisplayConfigSpecs failed to write maxRefreshRate: %d", result);
+ ALOGE("setDesiredDisplayConfigSpecs failed to write primaryRefreshRateMax: %d", result);
+ return result;
+ }
+ result = data.writeFloat(appRequestRefreshRateMin);
+ if (result != NO_ERROR) {
+ ALOGE("setDesiredDisplayConfigSpecs failed to write appRequestRefreshRateMin: %d",
+ result);
+ return result;
+ }
+ result = data.writeFloat(appRequestRefreshRateMax);
+ if (result != NO_ERROR) {
+ ALOGE("setDesiredDisplayConfigSpecs failed to write appRequestRefreshRateMax: %d",
+ result);
return result;
}
@@ -971,9 +986,14 @@
virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
- float* outMinRefreshRate,
- float* outMaxRefreshRate) {
- if (!outDefaultConfig || !outMinRefreshRate || !outMaxRefreshRate) return BAD_VALUE;
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) {
+ if (!outDefaultConfig || !outPrimaryRefreshRateMin || !outPrimaryRefreshRateMax ||
+ !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) {
+ return BAD_VALUE;
+ }
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
if (result != NO_ERROR) {
@@ -996,14 +1016,26 @@
ALOGE("getDesiredDisplayConfigSpecs failed to read defaultConfig: %d", result);
return result;
}
- result = reply.readFloat(outMinRefreshRate);
+ result = reply.readFloat(outPrimaryRefreshRateMin);
if (result != NO_ERROR) {
- ALOGE("getDesiredDisplayConfigSpecs failed to read minRefreshRate: %d", result);
+ ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMin: %d", result);
return result;
}
- result = reply.readFloat(outMaxRefreshRate);
+ result = reply.readFloat(outPrimaryRefreshRateMax);
if (result != NO_ERROR) {
- ALOGE("getDesiredDisplayConfigSpecs failed to read maxRefreshRate: %d", result);
+ ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMax: %d", result);
+ return result;
+ }
+ result = reply.readFloat(outAppRequestRefreshRateMin);
+ if (result != NO_ERROR) {
+ ALOGE("getDesiredDisplayConfigSpecs failed to read appRequestRefreshRateMin: %d",
+ result);
+ return result;
+ }
+ result = reply.readFloat(outAppRequestRefreshRateMax);
+ if (result != NO_ERROR) {
+ ALOGE("getDesiredDisplayConfigSpecs failed to read appRequestRefreshRateMax: %d",
+ result);
return result;
}
return reply.readInt32();
@@ -1835,20 +1867,38 @@
ALOGE("setDesiredDisplayConfigSpecs: failed to read defaultConfig: %d", result);
return result;
}
- float minRefreshRate;
- result = data.readFloat(&minRefreshRate);
+ float primaryRefreshRateMin;
+ result = data.readFloat(&primaryRefreshRateMin);
if (result != NO_ERROR) {
- ALOGE("setDesiredDisplayConfigSpecs: failed to read minRefreshRate: %d", result);
+ ALOGE("setDesiredDisplayConfigSpecs: failed to read primaryRefreshRateMin: %d",
+ result);
return result;
}
- float maxRefreshRate;
- result = data.readFloat(&maxRefreshRate);
+ float primaryRefreshRateMax;
+ result = data.readFloat(&primaryRefreshRateMax);
if (result != NO_ERROR) {
- ALOGE("setDesiredDisplayConfigSpecs: failed to read maxRefreshRate: %d", result);
+ ALOGE("setDesiredDisplayConfigSpecs: failed to read primaryRefreshRateMax: %d",
+ result);
return result;
}
- result = setDesiredDisplayConfigSpecs(displayToken, defaultConfig, minRefreshRate,
- maxRefreshRate);
+ float appRequestRefreshRateMin;
+ result = data.readFloat(&appRequestRefreshRateMin);
+ if (result != NO_ERROR) {
+ ALOGE("setDesiredDisplayConfigSpecs: failed to read appRequestRefreshRateMin: %d",
+ result);
+ return result;
+ }
+ float appRequestRefreshRateMax;
+ result = data.readFloat(&appRequestRefreshRateMax);
+ if (result != NO_ERROR) {
+ ALOGE("setDesiredDisplayConfigSpecs: failed to read appRequestRefreshRateMax: %d",
+ result);
+ return result;
+ }
+ result =
+ setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin,
+ primaryRefreshRateMax, appRequestRefreshRateMin,
+ appRequestRefreshRateMax);
if (result != NO_ERROR) {
ALOGE("setDesiredDisplayConfigSpecs: failed to call setDesiredDisplayConfigSpecs: "
"%d",
@@ -1862,11 +1912,16 @@
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> displayToken = data.readStrongBinder();
int32_t defaultConfig;
- float minRefreshRate;
- float maxRefreshRate;
+ float primaryRefreshRateMin;
+ float primaryRefreshRateMax;
+ float appRequestRefreshRateMin;
+ float appRequestRefreshRateMax;
- status_t result = getDesiredDisplayConfigSpecs(displayToken, &defaultConfig,
- &minRefreshRate, &maxRefreshRate);
+ status_t result =
+ getDesiredDisplayConfigSpecs(displayToken, &defaultConfig,
+ &primaryRefreshRateMin, &primaryRefreshRateMax,
+ &appRequestRefreshRateMin,
+ &appRequestRefreshRateMax);
if (result != NO_ERROR) {
ALOGE("getDesiredDisplayConfigSpecs: failed to get getDesiredDisplayConfigSpecs: "
"%d",
@@ -1879,14 +1934,28 @@
ALOGE("getDesiredDisplayConfigSpecs: failed to write defaultConfig: %d", result);
return result;
}
- result = reply->writeFloat(minRefreshRate);
+ result = reply->writeFloat(primaryRefreshRateMin);
if (result != NO_ERROR) {
- ALOGE("getDesiredDisplayConfigSpecs: failed to write minRefreshRate: %d", result);
+ ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMin: %d",
+ result);
return result;
}
- result = reply->writeFloat(maxRefreshRate);
+ result = reply->writeFloat(primaryRefreshRateMax);
if (result != NO_ERROR) {
- ALOGE("getDesiredDisplayConfigSpecs: failed to write maxRefreshRate: %d", result);
+ ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMax: %d",
+ result);
+ return result;
+ }
+ result = reply->writeFloat(appRequestRefreshRateMin);
+ if (result != NO_ERROR) {
+ ALOGE("getDesiredDisplayConfigSpecs: failed to write appRequestRefreshRateMin: %d",
+ result);
+ return result;
+ }
+ result = reply->writeFloat(appRequestRefreshRateMax);
+ if (result != NO_ERROR) {
+ ALOGE("getDesiredDisplayConfigSpecs: failed to write appRequestRefreshRateMax: %d",
+ result);
return result;
}
reply->writeInt32(result);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index d9cbeb7..a52f298 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1698,22 +1698,26 @@
status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t defaultConfig,
- float minRefreshRate,
- float maxRefreshRate) {
- return ComposerService::getComposerService()->setDesiredDisplayConfigSpecs(displayToken,
- defaultConfig,
- minRefreshRate,
- maxRefreshRate);
+ float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) {
+ return ComposerService::getComposerService()
+ ->setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin,
+ primaryRefreshRateMax, appRequestRefreshRateMin,
+ appRequestRefreshRateMax);
}
status_t SurfaceComposerClient::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
- float* outMinRefreshRate,
- float* outMaxRefreshRate) {
- return ComposerService::getComposerService()->getDesiredDisplayConfigSpecs(displayToken,
- outDefaultConfig,
- outMinRefreshRate,
- outMaxRefreshRate);
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) {
+ return ComposerService::getComposerService()
+ ->getDesiredDisplayConfigSpecs(displayToken, outDefaultConfig, outPrimaryRefreshRateMin,
+ outPrimaryRefreshRateMax, outAppRequestRefreshRateMin,
+ outAppRequestRefreshRateMax);
}
status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display,
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index b4a3fbe..0d33b3f 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -426,19 +426,36 @@
*/
virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) = 0;
- /*
- * Sets the refresh rate boundaries for display configuration.
- * For all other parameters, default configuration is used. The index for the default is
- * corresponding to the configs returned from getDisplayConfigs().
+ /* Sets the refresh rate boundaries for the display.
+ *
+ * The primary refresh rate range represents display manager's general guidance on the display
+ * configs we'll consider when switching refresh rates. Unless we get an explicit signal from an
+ * app, we should stay within this range.
+ *
+ * The app request refresh rate range allows us to consider more display configs when switching
+ * refresh rates. Although we should generally stay within the primary range, specific
+ * considerations, such as layer frame rate settings specified via the setFrameRate() api, may
+ * cause us to go outside the primary range. We never go outside the app request range. The app
+ * request range will be greater than or equal to the primary refresh rate range, never smaller.
+ *
+ * defaultConfig is used to narrow the list of display configs SurfaceFlinger will consider
+ * switching between. Only configs with a config group and resolution matching defaultConfig
+ * will be considered for switching. The defaultConfig index corresponds to the list of configs
+ * returned from getDisplayConfigs().
*/
virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig, float minRefreshRate,
- float maxRefreshRate) = 0;
+ int32_t defaultConfig,
+ float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) = 0;
virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
- float* outMinRefreshRate,
- float* outMaxRefreshRate) = 0;
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) = 0;
/*
* Gets whether brightness operations are supported on a display.
*
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 2fb9538..531aed7 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -118,21 +118,19 @@
// Shorthand for getDisplayConfigs element at getActiveConfig index.
static status_t getActiveDisplayConfig(const sp<IBinder>& display, DisplayConfig*);
- // Sets the refresh rate boundaries for display configuration.
- // For all other parameters, default configuration is used. The index for the default is
- // corresponting to the configs returned from getDisplayConfigs().
+ // Sets the refresh rate boundaries for the display.
static status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig, float minRefreshRate,
- float maxRefreshRate);
- // Gets the refresh rate boundaries for display configuration.
- // For all other parameters, default configuration is used. The index for the default is
- // corresponting to the configs returned from getDisplayConfigs().
- // The reason is passed in for telemetry tracking, and it corresponds to the list of all
- // the policy rules that were used.
+ int32_t defaultConfig, float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax);
+ // Gets the refresh rate boundaries for the display.
static status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
- float* outMinRefreshRate,
- float* outMaxRefreshRate);
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax);
// Gets the list of supported color modes for the given display
static status_t getDisplayColorModes(const sp<IBinder>& display,
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index d1d770e..6374d74 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -835,14 +835,19 @@
return NO_ERROR;
}
status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
- int32_t /*defaultConfig*/, float /*minRefreshRate*/,
- float /*maxRefreshRate*/) {
+ int32_t /*defaultConfig*/,
+ float /*primaryRefreshRateMin*/,
+ float /*primaryRefreshRateMax*/,
+ float /*appRequestRefreshRateMin*/,
+ float /*appRequestRefreshRateMax*/) {
return NO_ERROR;
}
status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
int32_t* /*outDefaultConfig*/,
- float* /*outMinRefreshRate*/,
- float* /*outMaxRefreshRate*/) override {
+ float* /*outPrimaryRefreshRateMin*/,
+ float* /*outPrimaryRefreshRateMax*/,
+ float* /*outAppRequestRefreshRateMin*/,
+ float* /*outAppRequestRefreshRateMax*/) override {
return NO_ERROR;
};
status_t notifyPowerHint(int32_t /*hintId*/) override { return NO_ERROR; }
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 5634adb..43e67c2 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -58,7 +58,7 @@
ATRACE_INT("ContentFPS", contentFramerate);
// Find the appropriate refresh rate with minimal error
- auto iter = min_element(mAvailableRefreshRates.cbegin(), mAvailableRefreshRates.cend(),
+ auto iter = min_element(mPrimaryRefreshRates.cbegin(), mPrimaryRefreshRates.cend(),
[contentFramerate](const auto& lhs, const auto& rhs) -> bool {
return std::abs(lhs->fps - contentFramerate) <
std::abs(rhs->fps - contentFramerate);
@@ -71,7 +71,7 @@
constexpr float MARGIN = 0.05f;
float ratio = (*iter)->fps / contentFramerate;
if (std::abs(std::round(ratio) - ratio) > MARGIN) {
- while (iter != mAvailableRefreshRates.cend()) {
+ while (iter != mPrimaryRefreshRates.cend()) {
ratio = (*iter)->fps / contentFramerate;
if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
@@ -110,7 +110,8 @@
// refresh rate.
if (layers.empty()) {
*touchConsidered = touchActive;
- return touchActive ? *mAvailableRefreshRates.back() : getCurrentRefreshRateByPolicyLocked();
+ return touchActive ? getMaxRefreshRateByPolicyLocked()
+ : getCurrentRefreshRateByPolicyLocked();
}
int noVoteLayers = 0;
@@ -135,25 +136,25 @@
}
}
- // 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 get get a touch event.
- if (touchActive && explicitDefaultVoteLayers == 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 (touchActive && explicitDefaultVoteLayers == 0 && explicitExactOrMultipleVoteLayers == 0) {
*touchConsidered = true;
- return *mAvailableRefreshRates.back();
+ return getMaxRefreshRateByPolicyLocked();
}
// Only if all layers want Min we should return Min
if (noVoteLayers + minVoteLayers == layers.size()) {
- return *mAvailableRefreshRates.front();
+ return getMinRefreshRateByPolicyLocked();
}
+ const Policy* policy = getCurrentPolicyLocked();
+
// Find the best refresh rate based on score
std::vector<std::pair<const RefreshRate*, float>> scores;
- scores.reserve(mAvailableRefreshRates.size());
+ scores.reserve(mAppRequestRefreshRates.size());
- for (const auto refreshRate : mAvailableRefreshRates) {
+ for (const auto refreshRate : mAppRequestRefreshRates) {
scores.emplace_back(refreshRate, 0.0f);
}
@@ -166,6 +167,15 @@
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 (!inPrimaryRange && layer.vote != LayerVoteType::ExplicitDefault &&
+ layer.vote != LayerVoteType::ExplicitExactOrMultiple) {
+ // Only layers with explicit 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;
@@ -249,6 +259,17 @@
? getBestRefreshRate(scores.rbegin(), scores.rend())
: getBestRefreshRate(scores.begin(), scores.end());
+ // 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 (touchActive && explicitDefaultVoteLayers == 0 &&
+ bestRefreshRate->fps < touchRefreshRate.fps) {
+ *touchConsidered = true;
+ return touchRefreshRate;
+ }
+
return *bestRefreshRate;
}
@@ -278,12 +299,20 @@
const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const {
std::lock_guard lock(mLock);
- return *mAvailableRefreshRates.front();
+ return getMinRefreshRateByPolicyLocked();
+}
+
+const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const {
+ return *mPrimaryRefreshRates.front();
}
const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
std::lock_guard lock(mLock);
- return *mAvailableRefreshRates.back();
+ return getMaxRefreshRateByPolicyLocked();
+}
+
+const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const {
+ return *mPrimaryRefreshRates.back();
}
const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const {
@@ -297,8 +326,8 @@
}
const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicyLocked() const {
- if (std::find(mAvailableRefreshRates.begin(), mAvailableRefreshRates.end(),
- mCurrentRefreshRate) != mAvailableRefreshRates.end()) {
+ if (std::find(mAppRequestRefreshRates.begin(), mAppRequestRefreshRates.end(),
+ mCurrentRefreshRate) != mAppRequestRefreshRates.end()) {
return *mCurrentRefreshRate;
}
return *mRefreshRates.at(getCurrentPolicyLocked()->defaultConfig);
@@ -320,7 +349,7 @@
const float fps = 1e9f / config->getVsyncPeriod();
mRefreshRates.emplace(configId,
std::make_unique<RefreshRate>(configId, config,
- base::StringPrintf("%2.ffps", fps), fps,
+ base::StringPrintf("%.0ffps", fps), fps,
RefreshRate::ConstructorTag(0)));
if (configId == currentConfigId) {
mCurrentRefreshRate = mRefreshRates.at(configId).get();
@@ -342,10 +371,11 @@
return false;
}
const RefreshRate& refreshRate = *iter->second;
- if (!refreshRate.inPolicy(policy.minRefreshRate, policy.maxRefreshRate)) {
+ if (!refreshRate.inPolicy(policy.primaryRange.min, policy.primaryRange.max)) {
return false;
}
- return true;
+ return policy.appRequestRange.min <= policy.primaryRange.min &&
+ policy.appRequestRange.max >= policy.primaryRange.max;
}
status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
@@ -392,7 +422,7 @@
bool RefreshRateConfigs::isConfigAllowed(HwcConfigIndexType config) const {
std::lock_guard lock(mLock);
- for (const RefreshRate* refreshRate : mAvailableRefreshRates) {
+ for (const RefreshRate* refreshRate : mAppRequestRefreshRates) {
if (refreshRate->configId == config) {
return true;
}
@@ -430,33 +460,44 @@
// 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 min %.2f max %.2f",
- policy->defaultConfig.value(), defaultConfig->getConfigGroup(), policy->minRefreshRate,
- policy->maxRefreshRate);
- getSortedRefreshRateList(
- [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
- const auto& hwcConfig = refreshRate.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);
- 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(policy->minRefreshRate, policy->maxRefreshRate);
- },
- &mAvailableRefreshRates);
+ auto filterRefreshRates = [&](float min, float max, const char* listName,
+ std::vector<const RefreshRate*>* outRefreshRates) {
+ getSortedRefreshRateList(
+ [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
+ const auto& hwcConfig = refreshRate.hwcConfig;
- std::string availableRefreshRates;
- for (const auto& refreshRate : mAvailableRefreshRates) {
- base::StringAppendF(&availableRefreshRates, "%s ", refreshRate->name.c_str());
- }
+ 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);
- ALOGV("Available refresh rates: %s", availableRefreshRates.c_str());
- LOG_ALWAYS_FATAL_IF(mAvailableRefreshRates.empty(),
- "No compatible display configs for default=%d min=%.0f max=%.0f",
- policy->defaultConfig.value(), policy->minRefreshRate,
- policy->maxRefreshRate);
+ 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);
}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index dea7e90..e8a7bef 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -107,18 +107,46 @@
std::unordered_map<HwcConfigIndexType, std::unique_ptr<const RefreshRate>>;
struct Policy {
+ struct Range {
+ float min = 0;
+ float max = std::numeric_limits<float>::max();
+
+ bool operator==(const Range& other) const {
+ return min == other.min && max == other.max;
+ }
+
+ bool operator!=(const Range& other) const { return !(*this == other); }
+ };
+
// The default config, used to ensure we only initiate display config switches within the
// same config group as defaultConfigId's group.
HwcConfigIndexType defaultConfig;
- // The min and max FPS allowed by the policy.
- float minRefreshRate = 0;
- float maxRefreshRate = std::numeric_limits<float>::max();
+ // The primary refresh rate range represents display manager's general guidance on the
+ // display configs we'll consider when switching refresh rates. Unless we get an explicit
+ // signal from an app, we should stay within this range.
+ Range primaryRange;
+ // The app request refresh rate range allows us to consider more display configs when
+ // switching refresh rates. Although we should generally stay within the primary range,
+ // specific considerations, such as layer frame rate settings specified via the
+ // setFrameRate() api, may cause us to go outside the primary range. We never go outside the
+ // app request range. The app request range will be greater than or equal to the primary
+ // refresh rate range, never smaller.
+ Range appRequestRange;
// Whether or not we switch config groups to get the best frame rate. Only used by tests.
bool allowGroupSwitching = false;
+ Policy() = default;
+ Policy(HwcConfigIndexType defaultConfig, const Range& range)
+ : Policy(defaultConfig, range, range) {}
+ Policy(HwcConfigIndexType defaultConfig, const Range& primaryRange,
+ const Range& appRequestRange)
+ : defaultConfig(defaultConfig),
+ primaryRange(primaryRange),
+ appRequestRange(appRequestRange) {}
+
bool operator==(const Policy& other) const {
- return defaultConfig == other.defaultConfig && minRefreshRate == other.minRefreshRate &&
- maxRefreshRate == other.maxRefreshRate &&
+ return defaultConfig == other.defaultConfig && primaryRange == other.primaryRange &&
+ appRequestRange == other.appRequestRange &&
allowGroupSwitching == other.allowGroupSwitching;
}
@@ -198,13 +226,15 @@
// Returns the lowest refresh rate supported by the device. This won't change at runtime.
const RefreshRate& getMinRefreshRate() const { return *mMinSupportedRefreshRate; }
- // Returns the lowest refresh rate according to the current policy. May change in runtime.
+ // Returns the lowest refresh rate according to the current policy. May change at runtime. Only
+ // uses the primary range, not the app request range.
const RefreshRate& getMinRefreshRateByPolicy() const EXCLUDES(mLock);
// Returns the highest refresh rate supported by the device. This won't change at runtime.
const RefreshRate& getMaxRefreshRate() const { return *mMaxSupportedRefreshRate; }
- // Returns the highest refresh rate according to the current policy. May change in runtime.
+ // Returns the highest refresh rate according to the current policy. May change at runtime. Only
+ // uses the primary range, not the app request range.
const RefreshRate& getMaxRefreshRateByPolicy() const EXCLUDES(mLock);
// Returns the current refresh rate
@@ -243,6 +273,14 @@
// display refresh period.
std::pair<nsecs_t, nsecs_t> getDisplayFrames(nsecs_t layerPeriod, nsecs_t displayPeriod) const;
+ // Returns the lowest refresh rate according to the current policy. May change at runtime. Only
+ // uses the primary range, not the app request range.
+ const RefreshRate& getMinRefreshRateByPolicyLocked() const REQUIRES(mLock);
+
+ // Returns the highest refresh rate according to the current policy. May change at runtime. Only
+ // uses the primary range, not the app request range.
+ const RefreshRate& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock);
+
// Returns the current refresh rate, if allowed. Otherwise the default that is allowed by
// the policy.
const RefreshRate& getCurrentRefreshRateByPolicyLocked() const REQUIRES(mLock);
@@ -254,9 +292,13 @@
// object is initialized.
AllRefreshRatesMapType mRefreshRates;
- // The list of refresh rates which are available in the current policy, ordered by vsyncPeriod
- // (the first element is the lowest refresh rate)
- std::vector<const RefreshRate*> mAvailableRefreshRates GUARDED_BY(mLock);
+ // The list of refresh rates in the primary range of the current policy, ordered by vsyncPeriod
+ // (the first element is the lowest refresh rate).
+ std::vector<const RefreshRate*> mPrimaryRefreshRates GUARDED_BY(mLock);
+
+ // The list of refresh rates in the app request range of the current policy, ordered by
+ // vsyncPeriod (the first element is the lowest refresh rate).
+ std::vector<const RefreshRate*> mAppRequestRefreshRates GUARDED_BY(mLock);
// The current config. This will change at runtime. This is set by SurfaceFlinger on
// the main thread, and read by the Scheduler (and other objects) on other threads.
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 86bb6eb..217c777 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -574,10 +574,8 @@
HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() {
ATRACE_CALL();
- // NOTE: If we remove the kernel idle timer, and use our internal idle timer, this
- // code will have to be refactored. 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 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)) {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 79ea97b..4ca2074 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1003,7 +1003,7 @@
} else {
const HwcConfigIndexType config(mode);
const float fps = mRefreshRateConfigs->getRefreshRateFromConfigId(config).getFps();
- const scheduler::RefreshRateConfigs::Policy policy{config, fps, fps};
+ const scheduler::RefreshRateConfigs::Policy policy{config, {fps, fps}};
constexpr bool kOverridePolicy = false;
return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
@@ -4383,17 +4383,19 @@
scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy();
StringAppendF(&result,
"DesiredDisplayConfigSpecs (DisplayManager): default config ID: %d"
- ", min: %.2f Hz, max: %.2f Hz",
- policy.defaultConfig.value(), policy.minRefreshRate, policy.maxRefreshRate);
+ ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n",
+ policy.defaultConfig.value(), policy.primaryRange.min, policy.primaryRange.max,
+ policy.appRequestRange.min, policy.appRequestRange.max);
StringAppendF(&result, "(config override by backdoor: %s)\n\n",
mDebugDisplayConfigSetByBackdoor ? "yes" : "no");
scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
if (currentPolicy != policy) {
StringAppendF(&result,
"DesiredDisplayConfigSpecs (Override): default config ID: %d"
- ", min: %.2f Hz, max: %.2f Hz\n\n",
- currentPolicy.defaultConfig.value(), currentPolicy.minRefreshRate,
- currentPolicy.maxRefreshRate);
+ ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n",
+ currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min,
+ currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min,
+ currentPolicy.appRequestRange.max);
}
mScheduler->dump(mAppConnectionHandle, result);
@@ -5928,9 +5930,11 @@
}
scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
- ALOGV("Setting desired display config specs: defaultConfig: %d min: %.f max: %.f",
- currentPolicy.defaultConfig.value(), currentPolicy.minRefreshRate,
- currentPolicy.maxRefreshRate);
+ 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): This hack triggers a notification that something has changed, so
// that listeners that care about a change in allowed configs can get the notification.
@@ -5963,8 +5967,11 @@
}
status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig, float minRefreshRate,
- float maxRefreshRate) {
+ int32_t defaultConfig,
+ float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) {
ATRACE_CALL();
if (!displayToken) {
@@ -5982,7 +5989,9 @@
return INVALID_OPERATION;
} else {
using Policy = scheduler::RefreshRateConfigs::Policy;
- const Policy policy{HwcConfigIndexType(defaultConfig), minRefreshRate, maxRefreshRate};
+ const Policy policy{HwcConfigIndexType(defaultConfig),
+ {primaryRefreshRateMin, primaryRefreshRateMax},
+ {appRequestRefreshRateMin, appRequestRefreshRateMax}};
constexpr bool kOverridePolicy = false;
return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
@@ -5994,11 +6003,14 @@
status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
- float* outMinRefreshRate,
- float* outMaxRefreshRate) {
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) {
ATRACE_CALL();
- if (!displayToken || !outDefaultConfig || !outMinRefreshRate || !outMaxRefreshRate) {
+ if (!displayToken || !outDefaultConfig || !outPrimaryRefreshRateMin ||
+ !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) {
return BAD_VALUE;
}
@@ -6012,8 +6024,10 @@
scheduler::RefreshRateConfigs::Policy policy =
mRefreshRateConfigs->getDisplayManagerPolicy();
*outDefaultConfig = policy.defaultConfig.value();
- *outMinRefreshRate = policy.minRefreshRate;
- *outMaxRefreshRate = policy.maxRefreshRate;
+ *outPrimaryRefreshRateMin = policy.primaryRange.min;
+ *outPrimaryRefreshRateMax = policy.primaryRange.max;
+ *outAppRequestRefreshRateMin = policy.appRequestRange.min;
+ *outAppRequestRefreshRateMax = policy.appRequestRange.max;
return NO_ERROR;
} else if (display->isVirtual()) {
return INVALID_OPERATION;
@@ -6023,8 +6037,10 @@
*outDefaultConfig = getHwComposer().getActiveConfigIndex(*displayId);
auto vsyncPeriod = getHwComposer().getActiveConfig(*displayId)->getVsyncPeriod();
- *outMinRefreshRate = 1e9f / vsyncPeriod;
- *outMaxRefreshRate = 1e9f / vsyncPeriod;
+ *outPrimaryRefreshRateMin = 1e9f / vsyncPeriod;
+ *outPrimaryRefreshRateMax = 1e9f / vsyncPeriod;
+ *outAppRequestRefreshRateMin = 1e9f / vsyncPeriod;
+ *outAppRequestRefreshRateMax = 1e9f / vsyncPeriod;
return NO_ERROR;
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 294a52f..f3984ed 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -493,10 +493,15 @@
const sp<IRegionSamplingListener>& listener) override;
status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, int32_t displayModeId,
- float minRefreshRate, float maxRefreshRate) override;
+ float primaryRefreshRateMin, float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) override;
status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t* outDefaultConfig, float* outMinRefreshRate,
- float* outMaxRefreshRate) override;
+ int32_t* outDefaultConfig,
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) override;
status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
bool* outSupport) const override;
status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) override;
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 507d28b..c136708 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -215,14 +215,21 @@
TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) {
const auto display = SurfaceComposerClient::getInternalDisplayToken();
int32_t defaultConfig;
- float minFps;
- float maxFps;
- status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig,
- &minFps, &maxFps);
+ float primaryFpsMin;
+ float primaryFpsMax;
+ float appRequestFpsMin;
+ float appRequestFpsMax;
+ status_t res =
+ SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig,
+ &primaryFpsMin, &primaryFpsMax,
+ &appRequestFpsMin,
+ &appRequestFpsMax);
ASSERT_EQ(res, NO_ERROR);
std::function<status_t()> condition = [=]() {
- return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig, minFps,
- maxFps);
+ return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig,
+ primaryFpsMin, primaryFpsMax,
+ appRequestFpsMin,
+ appRequestFpsMax);
};
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
}
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index 0ed2ffb..debfe83 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -39,11 +39,16 @@
TEST_F(RefreshRateRangeTest, setAllConfigs) {
int32_t initialDefaultConfig;
- float initialMin;
- float initialMax;
+ float initialPrimaryMin;
+ float initialPrimaryMax;
+ float initialAppRequestMin;
+ float initialAppRequestMax;
status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken,
&initialDefaultConfig,
- &initialMin, &initialMax);
+ &initialPrimaryMin,
+ &initialPrimaryMax,
+ &initialAppRequestMin,
+ &initialAppRequestMax);
ASSERT_EQ(res, NO_ERROR);
Vector<DisplayConfig> configs;
@@ -53,22 +58,33 @@
for (size_t i = 0; i < configs.size(); i++) {
res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, i,
configs[i].refreshRate,
+ configs[i].refreshRate,
+ configs[i].refreshRate,
configs[i].refreshRate);
ASSERT_EQ(res, NO_ERROR);
int defaultConfig;
- float minRefreshRate;
- float maxRefreshRate;
+ float primaryRefreshRateMin;
+ float primaryRefreshRateMax;
+ float appRequestRefreshRateMin;
+ float appRequestRefreshRateMax;
res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
- &minRefreshRate, &maxRefreshRate);
+ &primaryRefreshRateMin,
+ &primaryRefreshRateMax,
+ &appRequestRefreshRateMin,
+ &appRequestRefreshRateMax);
ASSERT_EQ(res, NO_ERROR);
ASSERT_EQ(defaultConfig, i);
- ASSERT_EQ(minRefreshRate, configs[i].refreshRate);
- ASSERT_EQ(maxRefreshRate, configs[i].refreshRate);
+ ASSERT_EQ(primaryRefreshRateMin, configs[i].refreshRate);
+ ASSERT_EQ(primaryRefreshRateMax, configs[i].refreshRate);
+ ASSERT_EQ(appRequestRefreshRateMin, configs[i].refreshRate);
+ ASSERT_EQ(appRequestRefreshRateMax, configs[i].refreshRate);
}
res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, initialDefaultConfig,
- initialMin, initialMax);
+ initialPrimaryMin, initialPrimaryMax,
+ initialAppRequestMin,
+ initialAppRequestMax);
ASSERT_EQ(res, NO_ERROR);
}
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 32c58ad..a03fd89 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -443,6 +443,8 @@
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
config.refreshRate,
+ config.refreshRate,
+ config.refreshRate,
config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
@@ -547,6 +549,8 @@
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
config.refreshRate,
+ config.refreshRate,
+ config.refreshRate,
config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
@@ -659,9 +663,11 @@
const auto& config = configs[i];
if (config.resolution.getWidth() == 800 && config.refreshRate == 1e9f / 11'111'111) {
EXPECT_EQ(NO_ERROR,
- SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
- configs[i].refreshRate,
- configs[i].refreshRate));
+ SurfaceComposerClient::
+ setDesiredDisplayConfigSpecs(display, i, configs[i].refreshRate,
+ configs[i].refreshRate,
+ configs[i].refreshRate,
+ configs[i].refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
@@ -706,6 +712,8 @@
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
config.refreshRate,
+ config.refreshRate,
+ config.refreshRate,
config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
@@ -751,6 +759,8 @@
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
config.refreshRate,
+ config.refreshRate,
+ config.refreshRate,
config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 2ceb89c..47addc8 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -166,8 +166,8 @@
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60OnlyConfigDevice,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HwcConfigIndexType(10), 60, 60}), 0);
- ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 20, 40}), 0);
+ ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HwcConfigIndexType(10), {60, 60}}), 0);
+ ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {20, 40}}), 0);
}
TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) {
@@ -201,7 +201,7 @@
ASSERT_EQ(mExpected60Config, minRate60);
ASSERT_EQ(mExpected60Config, performanceRate60);
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 60, 90}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60, 90}}), 0);
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
@@ -226,7 +226,7 @@
ASSERT_EQ(mExpected60Config, minRate60);
ASSERT_EQ(mExpected60Config, performanceRate60);
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 60, 90}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60, 90}}), 0);
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
@@ -248,7 +248,7 @@
ASSERT_EQ(mExpected60Config, minRate);
ASSERT_EQ(mExpected90Config, performanceRate);
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -271,7 +271,7 @@
EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
}
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
{
auto& current = refreshRateConfigs->getCurrentRefreshRate();
EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
@@ -298,7 +298,7 @@
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
EXPECT_EQ(mExpected60Config,
@@ -310,7 +310,7 @@
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
EXPECT_EQ(mExpected90Config,
@@ -321,7 +321,7 @@
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f)));
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 0, 120}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0, 120}}), 0);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
EXPECT_EQ(mExpected60Config,
@@ -407,7 +407,7 @@
&ignored));
lr.name = "";
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(mExpected60Config,
@@ -445,7 +445,7 @@
refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
&ignored));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(mExpected90Config,
@@ -483,7 +483,7 @@
refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
&ignored));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 0, 120}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0, 120}}), 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
@@ -1130,7 +1130,8 @@
lr1.desiredRefreshRate = 60.0f;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.name = "NoVote";
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.name = "60Hz Heuristic";
refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
EXPECT_EQ(true, touchConsidered);
@@ -1138,7 +1139,8 @@
lr1.desiredRefreshRate = 60.0f;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.name = "NoVote";
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.name = "60Hz Heuristic";
refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
EXPECT_EQ(false, touchConsidered);
@@ -1146,15 +1148,17 @@
lr1.desiredRefreshRate = 60.0f;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.name = "NoVote";
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.name = "60Hz Heuristic";
refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
EXPECT_EQ(true, touchConsidered);
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.desiredRefreshRate = 60.0f;
- lr1.name = "60Hz ExplicitExactrMultiple";
+ lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.name = "NoVote";
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.name = "60Hz Heuristic";
refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
EXPECT_EQ(false, touchConsidered);
}
@@ -1227,6 +1231,59 @@
.getConfigId());
}
+TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ layers[0].name = "Test layer";
+
+ // Return the config ID from calling getRefreshRateForContentV2() for a single layer with the
+ // given voteType and fps.
+ auto getFrameRate = [&](LayerVoteType voteType, float fps,
+ bool touchActive = false) -> HwcConfigIndexType {
+ layers[0].vote = voteType;
+ layers[0].desiredRefreshRate = fps;
+ bool touchConsidered;
+ return refreshRateConfigs->getRefreshRateForContentV2(layers, touchActive, &touchConsidered)
+ .getConfigId();
+ };
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 90.f}}),
+ 0);
+ bool touchConsidered;
+ EXPECT_EQ(HWC_CONFIG_ID_60,
+ refreshRateConfigs
+ ->getRefreshRateForContentV2({}, /*touchActive=*/false, &touchConsidered)
+ .getConfigId());
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f));
+
+ // Touch boost should be restricted to the primary range.
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f, /*touch=*/true));
+ // When we're higher than the primary range max due to a layer frame rate setting, touch boost
+ // shouldn't drag us back down to the primary range max.
+ EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f, /*touch=*/true));
+ EXPECT_EQ(HWC_CONFIG_ID_90,
+ getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f, /*touch=*/true));
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 60.f}}),
+ 0);
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f));
+}
+
} // namespace
} // namespace scheduler
} // namespace android