Loading services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +22 −15 Original line number Diff line number Diff line Loading @@ -330,18 +330,28 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( const bool hasExplicitVoteLayers = explicitDefaultVoteLayers > 0 || explicitExactOrMultipleVoteLayers > 0 || explicitExact > 0; const Policy* policy = getCurrentPolicyLocked(); const auto& defaultMode = mRefreshRates.at(policy->defaultMode); // If the default mode group is different from the group of current mode, // this means a layer requesting a seamed mode switch just disappeared and // we should switch back to the default group. // However if a seamed layer is still present we anchor around the group // of the current mode, in order to prevent unnecessary seamed mode switches // (e.g. when pausing a video playback). const auto anchorGroup = seamedFocusedLayers > 0 ? mCurrentRefreshRate->getModeGroup() : defaultMode->getModeGroup(); // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've // selected a refresh rate to see if we should apply touch boost. if (globalSignals.touch && !hasExplicitVoteLayers) { ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str()); setTouchConsidered(); return getMaxRefreshRateByPolicyLocked(); return getMaxRefreshRateByPolicyLocked(anchorGroup); } // If the primary range consists of a single refresh rate then we can only // move out the of range if layers explicitly request a different refresh // rate. const Policy* policy = getCurrentPolicyLocked(); const bool primaryRangeIsSingleRate = policy->primaryRange.min.equalsWithMargin(policy->primaryRange.max); Loading @@ -353,7 +363,9 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( } if (layers.empty() || noVoteLayers == layers.size()) { return getMaxRefreshRateByPolicyLocked(); const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); ALOGV("no layers with votes - choose %s", refreshRate.getName().c_str()); return refreshRate; } // Only if all layers want Min we should return Min Loading @@ -370,8 +382,6 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( scores.emplace_back(RefreshRateScore{refreshRate, 0.0f}); } const auto& defaultMode = mRefreshRates.at(policy->defaultMode); for (const auto& layer : layers) { ALOGV("Calculating score for %s (%s, weight %.2f, desired %.2f) ", layer.name.c_str(), layerVoteTypeString(layer.vote).c_str(), layer.weight, Loading Loading @@ -409,10 +419,7 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( // mode group otherwise. In second case, if the current mode group is different // from the default, this means a layer with seamlessness=SeamedAndSeamless has just // disappeared. const bool isInPolicyForDefault = seamedFocusedLayers > 0 ? scores[i].refreshRate->getModeGroup() == mCurrentRefreshRate->getModeGroup() : scores[i].refreshRate->getModeGroup() == defaultMode->getModeGroup(); const bool isInPolicyForDefault = scores[i].refreshRate->getModeGroup() == anchorGroup; if (layer.seamlessness == Seamlessness::Default && !isInPolicyForDefault) { ALOGV("%s ignores %s. Current mode = %s", formatLayerInfo(layer, weight).c_str(), scores[i].refreshRate->toString().c_str(), Loading Loading @@ -451,9 +458,9 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( // range instead of picking a random score from the app range. if (std::all_of(scores.begin(), scores.end(), [](RefreshRateScore score) { return score.score == 0; })) { ALOGV("layers not scored - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str()); return getMaxRefreshRateByPolicyLocked(); const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); ALOGV("layers not scored - choose %s", refreshRate.getName().c_str()); return refreshRate; } else { return *bestRefreshRate; } Loading @@ -463,7 +470,7 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( // 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(); const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); const bool touchBoostForExplicitExact = [&] { if (mSupportsFrameRateOverride) { Loading Loading @@ -646,10 +653,10 @@ RefreshRate RefreshRateConfigs::getMaxRefreshRateByPolicy() const { return getMaxRefreshRateByPolicyLocked(); } const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const { const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int anchorGroup) const { for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); it++) { const auto& refreshRate = (**it); if (mCurrentRefreshRate->getModeGroup() == refreshRate.getModeGroup()) { if (anchorGroup == refreshRate.getModeGroup()) { return refreshRate; } } Loading services/surfaceflinger/Scheduler/RefreshRateConfigs.h +5 −1 Original line number Diff line number Diff line Loading @@ -388,7 +388,11 @@ private: // 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); const RefreshRate& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock) { return getMaxRefreshRateByPolicyLocked(mCurrentRefreshRate->getModeGroup()); } const RefreshRate& getMaxRefreshRateByPolicyLocked(int anchorGroup) const REQUIRES(mLock); // Returns the current refresh rate, if allowed. Otherwise the default that is allowed by // the policy. Loading services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +11 −2 Original line number Diff line number Diff line Loading @@ -349,10 +349,19 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_noLayers) { EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}), 0); ASSERT_EQ(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}), NO_ERROR); EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); // We select max even when this will cause a non-seamless switch. refreshRateConfigs = std::make_unique<RefreshRateConfigs>(m60_90DeviceWithDifferentGroups, /*currentConfigId=*/HWC_CONFIG_ID_60); ASSERT_EQ(refreshRateConfigs->setDisplayManagerPolicy( {HWC_CONFIG_ID_90, /*allowGroupSwitching*/ true, {Fps(0), Fps(90)}}), NO_ERROR); EXPECT_EQ(mExpected90DifferentGroupConfig, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_90) { Loading Loading
services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +22 −15 Original line number Diff line number Diff line Loading @@ -330,18 +330,28 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( const bool hasExplicitVoteLayers = explicitDefaultVoteLayers > 0 || explicitExactOrMultipleVoteLayers > 0 || explicitExact > 0; const Policy* policy = getCurrentPolicyLocked(); const auto& defaultMode = mRefreshRates.at(policy->defaultMode); // If the default mode group is different from the group of current mode, // this means a layer requesting a seamed mode switch just disappeared and // we should switch back to the default group. // However if a seamed layer is still present we anchor around the group // of the current mode, in order to prevent unnecessary seamed mode switches // (e.g. when pausing a video playback). const auto anchorGroup = seamedFocusedLayers > 0 ? mCurrentRefreshRate->getModeGroup() : defaultMode->getModeGroup(); // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've // selected a refresh rate to see if we should apply touch boost. if (globalSignals.touch && !hasExplicitVoteLayers) { ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str()); setTouchConsidered(); return getMaxRefreshRateByPolicyLocked(); return getMaxRefreshRateByPolicyLocked(anchorGroup); } // If the primary range consists of a single refresh rate then we can only // move out the of range if layers explicitly request a different refresh // rate. const Policy* policy = getCurrentPolicyLocked(); const bool primaryRangeIsSingleRate = policy->primaryRange.min.equalsWithMargin(policy->primaryRange.max); Loading @@ -353,7 +363,9 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( } if (layers.empty() || noVoteLayers == layers.size()) { return getMaxRefreshRateByPolicyLocked(); const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); ALOGV("no layers with votes - choose %s", refreshRate.getName().c_str()); return refreshRate; } // Only if all layers want Min we should return Min Loading @@ -370,8 +382,6 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( scores.emplace_back(RefreshRateScore{refreshRate, 0.0f}); } const auto& defaultMode = mRefreshRates.at(policy->defaultMode); for (const auto& layer : layers) { ALOGV("Calculating score for %s (%s, weight %.2f, desired %.2f) ", layer.name.c_str(), layerVoteTypeString(layer.vote).c_str(), layer.weight, Loading Loading @@ -409,10 +419,7 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( // mode group otherwise. In second case, if the current mode group is different // from the default, this means a layer with seamlessness=SeamedAndSeamless has just // disappeared. const bool isInPolicyForDefault = seamedFocusedLayers > 0 ? scores[i].refreshRate->getModeGroup() == mCurrentRefreshRate->getModeGroup() : scores[i].refreshRate->getModeGroup() == defaultMode->getModeGroup(); const bool isInPolicyForDefault = scores[i].refreshRate->getModeGroup() == anchorGroup; if (layer.seamlessness == Seamlessness::Default && !isInPolicyForDefault) { ALOGV("%s ignores %s. Current mode = %s", formatLayerInfo(layer, weight).c_str(), scores[i].refreshRate->toString().c_str(), Loading Loading @@ -451,9 +458,9 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( // range instead of picking a random score from the app range. if (std::all_of(scores.begin(), scores.end(), [](RefreshRateScore score) { return score.score == 0; })) { ALOGV("layers not scored - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str()); return getMaxRefreshRateByPolicyLocked(); const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); ALOGV("layers not scored - choose %s", refreshRate.getName().c_str()); return refreshRate; } else { return *bestRefreshRate; } Loading @@ -463,7 +470,7 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( // 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(); const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); const bool touchBoostForExplicitExact = [&] { if (mSupportsFrameRateOverride) { Loading Loading @@ -646,10 +653,10 @@ RefreshRate RefreshRateConfigs::getMaxRefreshRateByPolicy() const { return getMaxRefreshRateByPolicyLocked(); } const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const { const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int anchorGroup) const { for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); it++) { const auto& refreshRate = (**it); if (mCurrentRefreshRate->getModeGroup() == refreshRate.getModeGroup()) { if (anchorGroup == refreshRate.getModeGroup()) { return refreshRate; } } Loading
services/surfaceflinger/Scheduler/RefreshRateConfigs.h +5 −1 Original line number Diff line number Diff line Loading @@ -388,7 +388,11 @@ private: // 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); const RefreshRate& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock) { return getMaxRefreshRateByPolicyLocked(mCurrentRefreshRate->getModeGroup()); } const RefreshRate& getMaxRefreshRateByPolicyLocked(int anchorGroup) const REQUIRES(mLock); // Returns the current refresh rate, if allowed. Otherwise the default that is allowed by // the policy. Loading
services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +11 −2 Original line number Diff line number Diff line Loading @@ -349,10 +349,19 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_noLayers) { EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}), 0); ASSERT_EQ(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {Fps(60), Fps(60)}}), NO_ERROR); EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); // We select max even when this will cause a non-seamless switch. refreshRateConfigs = std::make_unique<RefreshRateConfigs>(m60_90DeviceWithDifferentGroups, /*currentConfigId=*/HWC_CONFIG_ID_60); ASSERT_EQ(refreshRateConfigs->setDisplayManagerPolicy( {HWC_CONFIG_ID_90, /*allowGroupSwitching*/ true, {Fps(0), Fps(90)}}), NO_ERROR); EXPECT_EQ(mExpected90DifferentGroupConfig, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_90) { Loading