Loading services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +0 −2 Original line number Diff line number Diff line Loading @@ -212,7 +212,5 @@ void LayerHistoryV2::clear() { for (const auto& [layer, info] : activeLayers()) { info->clearHistory(); } mActiveLayersEnd = 0; } } // namespace android::scheduler::impl services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +38 −23 Original line number Diff line number Diff line Loading @@ -23,6 +23,9 @@ #include <chrono> #include <cmath> #undef LOG_TAG #define LOG_TAG "RefreshRateConfigs" namespace android::scheduler { using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType; Loading Loading @@ -95,22 +98,19 @@ std::pair<nsecs_t, nsecs_t> RefreshRateConfigs::getDisplayFrames(nsecs_t layerPe } const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( const std::vector<LayerRequirement>& layers, bool touchActive) const { const std::vector<LayerRequirement>& layers, bool touchActive, bool* touchConsidered) const { ATRACE_CALL(); ALOGV("getRefreshRateForContent %zu layers", layers.size()); *touchConsidered = false; std::lock_guard lock(mLock); // For now if the touch is active return the peak refresh rate // This should be optimized to consider other layers as well. if (touchActive) { return *mAvailableRefreshRates.back(); } // If there are not layers, there is not content detection, so return the current // refresh rate. if (layers.empty()) { return getCurrentRefreshRateByPolicyLocked(); *touchConsidered = touchActive; return touchActive ? *mAvailableRefreshRates.back() : getCurrentRefreshRateByPolicyLocked(); } int noVoteLayers = 0; Loading @@ -118,17 +118,30 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( int maxVoteLayers = 0; int explicitDefaultVoteLayers = 0; int explicitExactOrMultipleVoteLayers = 0; float maxExplicitWeight = 0; for (const auto& layer : layers) { if (layer.vote == LayerVoteType::NoVote) if (layer.vote == LayerVoteType::NoVote) { noVoteLayers++; else if (layer.vote == LayerVoteType::Min) } else if (layer.vote == LayerVoteType::Min) { minVoteLayers++; else if (layer.vote == LayerVoteType::Max) } else if (layer.vote == LayerVoteType::Max) { maxVoteLayers++; else if (layer.vote == LayerVoteType::ExplicitDefault) } else if (layer.vote == LayerVoteType::ExplicitDefault) { explicitDefaultVoteLayers++; else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple) maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); } else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple) { explicitExactOrMultipleVoteLayers++; maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); } } // 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) { *touchConsidered = true; return *mAvailableRefreshRates.back(); } // Only if all layers want Min we should return Min Loading Loading @@ -168,16 +181,17 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( const auto layerPeriod = round<nsecs_t>(1e9f / layer.desiredRefreshRate); if (layer.vote == LayerVoteType::ExplicitDefault) { const auto layerScore = [&]() { const auto [displayFramesQuot, displayFramesRem] = getDisplayFrames(layerPeriod, displayPeriod); if (displayFramesQuot == 0) { // Layer desired refresh rate is higher the display rate. return static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod); } return 1.0f - (static_cast<float>(displayFramesRem) / static_cast<float>(layerPeriod)); // Find the actual rate the layer will render, assuming // that layerPeriod is the minimal time to render a frame auto actualLayerPeriod = displayPeriod; int multiplier = 1; while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) { multiplier++; actualLayerPeriod = displayPeriod * multiplier; } return std::min(1.0f, static_cast<float>(layerPeriod) / static_cast<float>(actualLayerPeriod)); }(); ALOGV("%s (ExplicitDefault, weight %.2f) %.2fHz gives %s score of %.2f", Loading Loading @@ -240,6 +254,7 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( template <typename Iter> const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const { constexpr auto EPSILON = 0.001f; const RefreshRate* bestRefreshRate = begin->first; float max = begin->second; for (auto i = begin; i != end; ++i) { Loading @@ -248,7 +263,7 @@ const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) ATRACE_INT(refreshRate->name.c_str(), round<int>(score * 100)); if (score > max) { if (score > max * (1 + EPSILON)) { max = score; bestRefreshRate = refreshRate; } Loading services/surfaceflinger/Scheduler/RefreshRateConfigs.h +4 −2 Original line number Diff line number Diff line Loading @@ -137,9 +137,11 @@ public: // Returns the refresh rate that fits best to the given layers. This function also gets a // boolean flag that indicates whether user touched the screen recently to be factored in when // choosing the refresh rate. // choosing the refresh rate and returns whether the refresh rate was chosen as a result of // a touch event. const RefreshRate& getRefreshRateForContentV2(const std::vector<LayerRequirement>& layers, bool touchActive) const EXCLUDES(mLock); bool touchActive, bool* touchConsidered) const EXCLUDES(mLock); // Returns all the refresh rates supported by the device. This won't change at runtime. const AllRefreshRatesMapType& getAllRefreshRates() const EXCLUDES(mLock); Loading services/surfaceflinger/Scheduler/Scheduler.cpp +16 −5 Original line number Diff line number Diff line Loading @@ -483,7 +483,7 @@ void Scheduler::notifyTouchEvent() { // that is currently on top. b/142507166 will give us this capability. std::lock_guard<std::mutex> lock(mFeatureStateLock); if (mLayerHistory) { mLayerHistory->clear(); // Layer History will be cleared based on RefreshRateConfigs::getRefreshRateForContentV2 mTouchTimer->reset(); Loading Loading @@ -620,10 +620,21 @@ HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() { return mRefreshRateConfigs.getRefreshRateForContent(mFeatures.contentRequirements).configId; } return mRefreshRateConfigs bool touchConsidered; const auto& ret = mRefreshRateConfigs .getRefreshRateForContentV2(mFeatures.contentRequirements, mTouchTimer && mFeatures.touch == TouchState::Active) mTouchTimer && mFeatures.touch == TouchState::Active, &touchConsidered) .configId; if (touchConsidered) { // Clear layer history if refresh rate was selected based on touch to allow // the hueristic to pick up with the new rate. mLayerHistory->clear(); } return ret; } std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() { Loading services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +294 −91 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +0 −2 Original line number Diff line number Diff line Loading @@ -212,7 +212,5 @@ void LayerHistoryV2::clear() { for (const auto& [layer, info] : activeLayers()) { info->clearHistory(); } mActiveLayersEnd = 0; } } // namespace android::scheduler::impl
services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +38 −23 Original line number Diff line number Diff line Loading @@ -23,6 +23,9 @@ #include <chrono> #include <cmath> #undef LOG_TAG #define LOG_TAG "RefreshRateConfigs" namespace android::scheduler { using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType; Loading Loading @@ -95,22 +98,19 @@ std::pair<nsecs_t, nsecs_t> RefreshRateConfigs::getDisplayFrames(nsecs_t layerPe } const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( const std::vector<LayerRequirement>& layers, bool touchActive) const { const std::vector<LayerRequirement>& layers, bool touchActive, bool* touchConsidered) const { ATRACE_CALL(); ALOGV("getRefreshRateForContent %zu layers", layers.size()); *touchConsidered = false; std::lock_guard lock(mLock); // For now if the touch is active return the peak refresh rate // This should be optimized to consider other layers as well. if (touchActive) { return *mAvailableRefreshRates.back(); } // If there are not layers, there is not content detection, so return the current // refresh rate. if (layers.empty()) { return getCurrentRefreshRateByPolicyLocked(); *touchConsidered = touchActive; return touchActive ? *mAvailableRefreshRates.back() : getCurrentRefreshRateByPolicyLocked(); } int noVoteLayers = 0; Loading @@ -118,17 +118,30 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( int maxVoteLayers = 0; int explicitDefaultVoteLayers = 0; int explicitExactOrMultipleVoteLayers = 0; float maxExplicitWeight = 0; for (const auto& layer : layers) { if (layer.vote == LayerVoteType::NoVote) if (layer.vote == LayerVoteType::NoVote) { noVoteLayers++; else if (layer.vote == LayerVoteType::Min) } else if (layer.vote == LayerVoteType::Min) { minVoteLayers++; else if (layer.vote == LayerVoteType::Max) } else if (layer.vote == LayerVoteType::Max) { maxVoteLayers++; else if (layer.vote == LayerVoteType::ExplicitDefault) } else if (layer.vote == LayerVoteType::ExplicitDefault) { explicitDefaultVoteLayers++; else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple) maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); } else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple) { explicitExactOrMultipleVoteLayers++; maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); } } // 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) { *touchConsidered = true; return *mAvailableRefreshRates.back(); } // Only if all layers want Min we should return Min Loading Loading @@ -168,16 +181,17 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( const auto layerPeriod = round<nsecs_t>(1e9f / layer.desiredRefreshRate); if (layer.vote == LayerVoteType::ExplicitDefault) { const auto layerScore = [&]() { const auto [displayFramesQuot, displayFramesRem] = getDisplayFrames(layerPeriod, displayPeriod); if (displayFramesQuot == 0) { // Layer desired refresh rate is higher the display rate. return static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod); } return 1.0f - (static_cast<float>(displayFramesRem) / static_cast<float>(layerPeriod)); // Find the actual rate the layer will render, assuming // that layerPeriod is the minimal time to render a frame auto actualLayerPeriod = displayPeriod; int multiplier = 1; while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) { multiplier++; actualLayerPeriod = displayPeriod * multiplier; } return std::min(1.0f, static_cast<float>(layerPeriod) / static_cast<float>(actualLayerPeriod)); }(); ALOGV("%s (ExplicitDefault, weight %.2f) %.2fHz gives %s score of %.2f", Loading Loading @@ -240,6 +254,7 @@ const RefreshRate& RefreshRateConfigs::getRefreshRateForContentV2( template <typename Iter> const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const { constexpr auto EPSILON = 0.001f; const RefreshRate* bestRefreshRate = begin->first; float max = begin->second; for (auto i = begin; i != end; ++i) { Loading @@ -248,7 +263,7 @@ const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) ATRACE_INT(refreshRate->name.c_str(), round<int>(score * 100)); if (score > max) { if (score > max * (1 + EPSILON)) { max = score; bestRefreshRate = refreshRate; } Loading
services/surfaceflinger/Scheduler/RefreshRateConfigs.h +4 −2 Original line number Diff line number Diff line Loading @@ -137,9 +137,11 @@ public: // Returns the refresh rate that fits best to the given layers. This function also gets a // boolean flag that indicates whether user touched the screen recently to be factored in when // choosing the refresh rate. // choosing the refresh rate and returns whether the refresh rate was chosen as a result of // a touch event. const RefreshRate& getRefreshRateForContentV2(const std::vector<LayerRequirement>& layers, bool touchActive) const EXCLUDES(mLock); bool touchActive, bool* touchConsidered) const EXCLUDES(mLock); // Returns all the refresh rates supported by the device. This won't change at runtime. const AllRefreshRatesMapType& getAllRefreshRates() const EXCLUDES(mLock); Loading
services/surfaceflinger/Scheduler/Scheduler.cpp +16 −5 Original line number Diff line number Diff line Loading @@ -483,7 +483,7 @@ void Scheduler::notifyTouchEvent() { // that is currently on top. b/142507166 will give us this capability. std::lock_guard<std::mutex> lock(mFeatureStateLock); if (mLayerHistory) { mLayerHistory->clear(); // Layer History will be cleared based on RefreshRateConfigs::getRefreshRateForContentV2 mTouchTimer->reset(); Loading Loading @@ -620,10 +620,21 @@ HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() { return mRefreshRateConfigs.getRefreshRateForContent(mFeatures.contentRequirements).configId; } return mRefreshRateConfigs bool touchConsidered; const auto& ret = mRefreshRateConfigs .getRefreshRateForContentV2(mFeatures.contentRequirements, mTouchTimer && mFeatures.touch == TouchState::Active) mTouchTimer && mFeatures.touch == TouchState::Active, &touchConsidered) .configId; if (touchConsidered) { // Clear layer history if refresh rate was selected based on touch to allow // the hueristic to pick up with the new rate. mLayerHistory->clear(); } return ret; } std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() { Loading
services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +294 −91 File changed.Preview size limit exceeded, changes collapsed. Show changes