Split refresh rate range into two ranges

To prevent low-priority refresh rate considerations from overriding the
app frame rate as specified via the new setFrameRate() api, split the
display refresh rate range into "primary" and "app request" ranges. The
primary range includes the low priority considerations, while the app
request range removes two lower priority considerations.

In general, surface flinger will keep the display refresh rate within
the primary range, but layers with frame rate settings via the
setFrameRate() api may cause surface flinger to pick a refresh rate
outside the primary range. Surface flinger will never choose a refresh
rate outside the app request range specified by display manager.

Bug: 148978562

Test: - Added a new unit test to DisplayModeDirectorTest to verify that
        display manager strips lower priority considerations when
        deciding the app request range.

- Added a new unit test to RefreshRateConfigsTest to verify
  RefreshRateConfigs handles the primary vs app request range
  correctly.

- Manual test: Confirmed that with the "force 90Hz refresh rate" option
  turned on, we don't switch to 60Hz when playing a 60Hz video.

- Manual test: Confirmed that with the "force 90Hz refresh rate" option
  turned on, when an app calls setFrameRate(60), we stay at 60Hz.

- Manual test: Modified a Pixel 4 XL to prefer 60Hz in low brightness,
  entered low brightness, and confirmed we don't touch boost to 90Hz.

- Manual test: Confirmed that Maps stays at 60Hz on Pixel 4.

- Manual test: Turned on verbose logs in RefreshRateConfigs.cpp,
  confirmed they look good.

- Manual test: Inspected dumpsys output, confirmed the primary and
  app request refresh rate ranges are printed correctly.

Change-Id: Ib16cc9b6158efa575cdbfbb7a0ad014008a3e5af
This commit is contained in:
Steven Thomas 2020-04-13 21:09:28 -07:00
parent aa8c701198
commit f734df4201
14 changed files with 465 additions and 180 deletions

View file

@ -931,8 +931,11 @@ public:
}
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ status_t BnSurfaceComposer::onTransact(
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 @@ status_t BnSurfaceComposer::onTransact(
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 @@ status_t BnSurfaceComposer::onTransact(
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);

View file

@ -1698,22 +1698,26 @@ int SurfaceComposerClient::getActiveConfig(const sp<IBinder>& display) {
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,

View file

@ -426,19 +426,36 @@ public:
*/
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.
*

View file

@ -118,21 +118,19 @@ public:
// 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,

View file

@ -835,14 +835,19 @@ public:
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; }

View file

@ -58,7 +58,7 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContent(
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 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContent(
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 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2(
// refresh rate.
if (layers.empty()) {
*touchConsidered = touchActive;
return touchActive ? *mAvailableRefreshRates.back() : getCurrentRefreshRateByPolicyLocked();
return touchActive ? getMaxRefreshRateByPolicyLocked()
: getCurrentRefreshRateByPolicyLocked();
}
int noVoteLayers = 0;
@ -135,25 +136,25 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2(
}
}
// 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 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2(
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 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2(
? 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 AllRefreshRatesMapType& RefreshRateConfigs::getAllRefreshRates() const {
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::getCurrentRefreshRateByPolicy() const {
}
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 @@ RefreshRateConfigs::RefreshRateConfigs(
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 @@ bool RefreshRateConfigs::isPolicyValid(const Policy& policy) {
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 @@ RefreshRateConfigs::Policy RefreshRateConfigs::getDisplayManagerPolicy() const {
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 @@ 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 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

View file

@ -107,18 +107,46 @@ public:
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 @@ public:
// 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 @@ private:
// 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 @@ private:
// 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.

View file

@ -574,10 +574,8 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO
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)) {

View file

@ -1002,7 +1002,7 @@ status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mo
} 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);
@ -4371,17 +4371,19 @@ void SurfaceFlinger::dumpVSync(std::string& result) const {
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);
@ -5916,9 +5918,11 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(
}
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.
@ -5951,8 +5955,11 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(
}
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) {
@ -5970,7 +5977,9 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp<IBinder>& display
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);
@ -5982,11 +5991,14 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp<IBinder>& display
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;
}
@ -6000,8 +6012,10 @@ status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp<IBinder>& display
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;
@ -6011,8 +6025,10 @@ status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp<IBinder>& display
*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;
}
}

View file

@ -493,10 +493,15 @@ private:
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;

View file

@ -215,14 +215,21 @@ TEST_F(CredentialsTest, GetDisplayNativePrimariesTest) {
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));
}

View file

@ -39,11 +39,16 @@ protected:
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;
@ -52,23 +57,34 @@ TEST_F(RefreshRateRangeTest, setAllConfigs) {
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);
}

View file

@ -442,6 +442,8 @@ protected:
if (config.resolution.getWidth() == 800) {
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
config.refreshRate,
config.refreshRate,
config.refreshRate,
config.refreshRate));
waitForDisplayTransaction();
@ -546,6 +548,8 @@ protected:
if (config.refreshRate == 1e9f / 11'111'111) {
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
config.refreshRate,
config.refreshRate,
config.refreshRate,
config.refreshRate));
waitForDisplayTransaction();
@ -659,9 +663,11 @@ protected:
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;
@ -705,6 +711,8 @@ protected:
if (config.refreshRate == 1e9f / 8'333'333) {
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
config.refreshRate,
config.refreshRate,
config.refreshRate,
config.refreshRate));
waitForDisplayTransaction();
@ -750,6 +758,8 @@ protected:
if (config.resolution.getWidth() == 1600 && config.refreshRate == 1e9f / 11'111'111) {
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
config.refreshRate,
config.refreshRate,
config.refreshRate,
config.refreshRate));
waitForDisplayTransaction();

View file

@ -166,8 +166,8 @@ TEST_F(RefreshRateConfigsTest, invalidPolicy) {
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 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differe
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 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differe
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 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_policyChange) {
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 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getCurrentRefreshRate) {
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 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) {
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 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) {
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 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) {
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 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) {
&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 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) {
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 @@ TEST_F(RefreshRateConfigsTest, getRefreshRateForContentV2_60_90) {
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 @@ TEST_F(RefreshRateConfigsTest, touchConsidered) {
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 @@ TEST_F(RefreshRateConfigsTest, touchConsidered) {
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 @@ TEST_F(RefreshRateConfigsTest, touchConsidered) {
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 @@ TEST_F(RefreshRateConfigsTest, groupSwitching) {
.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