Loading services/surfaceflinger/Layer.cpp +9 −2 Original line number Diff line number Diff line Loading @@ -1353,8 +1353,15 @@ void Layer::updateTreeHasFrameRateVote() { // First traverse the tree and count how many layers has votes int layersWithVote = 0; traverseTree([&layersWithVote](Layer* layer) { if (layer->mCurrentState.frameRate.rate > 0 || layer->mCurrentState.frameRate.type == FrameRateCompatibility::NoVote) { const auto layerVotedWithDefaultCompatibility = layer->mCurrentState.frameRate.rate > 0 && layer->mCurrentState.frameRate.type == FrameRateCompatibility::Default; const auto layerVotedWithNoVote = layer->mCurrentState.frameRate.type == FrameRateCompatibility::NoVote; // We do not count layers that are ExactOrMultiple for the same reason // we are allowing touch boost for those layers. See // RefreshRateConfigs::getBestRefreshRate for more details. if (layerVotedWithDefaultCompatibility || layerVotedWithNoVote) { layersWithVote++; } }); Loading services/surfaceflinger/Scheduler/LayerHistory.h +9 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,8 @@ public: // Sets the display size. Client is responsible for synchronization. virtual void setDisplayArea(uint32_t displayArea) = 0; virtual void setConfigChangePending(bool pending) = 0; // Marks the layer as active, and records the given state to its history. virtual void record(Layer*, nsecs_t presentTime, nsecs_t now) = 0; Loading @@ -78,6 +80,8 @@ public: void setDisplayArea(uint32_t /*displayArea*/) override {} void setConfigChangePending(bool /*pending*/) override {} // Marks the layer as active, and records the given state to its history. void record(Layer*, nsecs_t presentTime, nsecs_t now) override; Loading Loading @@ -134,6 +138,8 @@ public: // Sets the display size. Client is responsible for synchronization. void setDisplayArea(uint32_t displayArea) override { mDisplayArea = displayArea; } void setConfigChangePending(bool pending) override { mConfigChangePending = pending; } // Marks the layer as active, and records the given state to its history. void record(Layer*, nsecs_t presentTime, nsecs_t now) override; Loading Loading @@ -178,6 +184,9 @@ private: // Whether to use priority sent from WindowManager to determine the relevancy of the layer. const bool mUseFrameRatePriority; // Whether a config change is in progress or not std::atomic<bool> mConfigChangePending = false; }; } // namespace impl Loading services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -103,7 +103,7 @@ void LayerHistoryV2::record(Layer* layer, nsecs_t presentTime, nsecs_t now) { LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer); const auto& info = it->second; info->setLastPresentTime(presentTime, now); info->setLastPresentTime(presentTime, now, mConfigChangePending); // Activate layer if inactive. if (const auto end = activeLayers().end(); it >= end) { Loading services/surfaceflinger/Scheduler/LayerInfoV2.cpp +65 −36 Original line number Diff line number Diff line Loading @@ -34,12 +34,15 @@ LayerInfoV2::LayerInfoV2(const std::string& name, nsecs_t highRefreshRatePeriod, mDefaultVote(defaultVote), mLayerVote({defaultVote, 0.0f}) {} void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now) { void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, bool pendingConfigChange) { lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0)); mLastUpdatedTime = std::max(lastPresentTime, now); FrameTimeData frameTime = {.presetTime = lastPresentTime, .queueTime = mLastUpdatedTime}; FrameTimeData frameTime = {.presetTime = lastPresentTime, .queueTime = mLastUpdatedTime, .pendingConfigChange = pendingConfigChange}; mFrameTimes.push_back(frameTime); if (mFrameTimes.size() > HISTORY_SIZE) { Loading @@ -47,23 +50,28 @@ void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now) { } } bool LayerInfoV2::isFrequent(nsecs_t now) const { bool LayerInfoV2::isFrequent(nsecs_t now) { mLastReportedIsFrequent = [&] { for (auto it = mFrameTimes.crbegin(); it != mFrameTimes.crend(); ++it) { if (now - it->queueTime >= MAX_FREQUENT_LAYER_PERIOD_NS.count()) { ALOGV("%s infrequent (last frame is %.2fms ago", mName.c_str(), ALOGV("%s infrequent (last frame is %.2fms ago)", mName.c_str(), (now - mFrameTimes.back().queueTime) / 1e6f); return false; } const auto numFrames = std::distance(mFrameTimes.crbegin(), it + 1); if (numFrames >= FREQUENT_LAYER_WINDOW_SIZE) { ALOGV("%s frequent (burst of %zu frames", mName.c_str(), numFrames); ALOGV("%s frequent (burst of %zu frames)", mName.c_str(), numFrames); return true; } } ALOGV("%s infrequent (not enough frames %zu)", mName.c_str(), mFrameTimes.size()); return false; ALOGV("%s %sfrequent (not enough frames %zu)", mName.c_str(), mLastReportedIsFrequent ? "" : "in", mFrameTimes.size()); return mLastReportedIsFrequent; }(); return mLastReportedIsFrequent; } bool LayerInfoV2::hasEnoughDataForHeuristic() const { Loading @@ -80,21 +88,20 @@ bool LayerInfoV2::hasEnoughDataForHeuristic() const { return true; } std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { static constexpr float MARGIN = 1.0f; // 1Hz if (!hasEnoughDataForHeuristic()) { ALOGV("Not enough data"); return std::nullopt; } // Calculate the refresh rate by finding the average delta between frames std::pair<nsecs_t, bool> LayerInfoV2::calculateAverageFrameTime() const { nsecs_t totalPresentTimeDeltas = 0; nsecs_t totalQueueTimeDeltas = 0; auto missingPresentTime = false; bool missingPresentTime = false; int numFrames = 0; for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) { // Ignore frames captured during a config change if (it->pendingConfigChange || (it + 1)->pendingConfigChange) { continue; } totalQueueTimeDeltas += std::max(((it + 1)->queueTime - it->queueTime), mHighRefreshRatePeriod); numFrames++; if (it->presetTime == 0 || (it + 1)->presetTime == 0) { missingPresentTime = true; Loading @@ -105,11 +112,6 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod); } // If there are no presentation timestamps provided we can't calculate the refresh rate if (missingPresentTime && mLastReportedRefreshRate == 0) { return std::nullopt; } // Calculate the average frame time based on presentation timestamps. If those // doesn't exist, we look at the time the buffer was queued only. We can do that only if // we calculated a refresh rate based on presentation timestamps in the past. The reason Loading @@ -117,13 +119,18 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { // when implementing render ahead for specific refresh rates. When hwui no longer provides // presentation timestamps we look at the queue time to see if the current refresh rate still // matches the content. const float averageFrameTime = const auto averageFrameTime = static_cast<float>(missingPresentTime ? totalQueueTimeDeltas : totalPresentTimeDeltas) / (mFrameTimes.size() - 1); numFrames; return {static_cast<nsecs_t>(averageFrameTime), missingPresentTime}; } // Now once we calculated the refresh rate we need to make sure that all the frames we captured // are evenly distributed and we don't calculate the average across some burst of frames. bool LayerInfoV2::isRefreshRateStable(nsecs_t averageFrameTime, bool missingPresentTime) const { for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) { // Ignore frames captured during a config change if (it->pendingConfigChange || (it + 1)->pendingConfigChange) { continue; } const auto presentTimeDeltas = [&] { const auto delta = missingPresentTime ? (it + 1)->queueTime - it->queueTime : (it + 1)->presetTime - it->presetTime; Loading @@ -131,8 +138,30 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { }(); if (std::abs(presentTimeDeltas - averageFrameTime) > 2 * averageFrameTime) { return false; } } return true; } std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { static constexpr float MARGIN = 1.0f; // 1Hz if (!hasEnoughDataForHeuristic()) { ALOGV("Not enough data"); return std::nullopt; } const auto [averageFrameTime, missingPresentTime] = calculateAverageFrameTime(); // If there are no presentation timestamps provided we can't calculate the refresh rate if (missingPresentTime && mLastReportedRefreshRate == 0) { return std::nullopt; } if (!isRefreshRateStable(averageFrameTime, missingPresentTime)) { return std::nullopt; } const auto refreshRate = 1e9f / averageFrameTime; Loading services/surfaceflinger/Scheduler/LayerInfoV2.h +13 −5 Original line number Diff line number Diff line Loading @@ -47,9 +47,7 @@ class LayerInfoV2 { // is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in // favor of a low refresh rate. static constexpr size_t FREQUENT_LAYER_WINDOW_SIZE = 3; static constexpr float MIN_FPS_FOR_FREQUENT_LAYER = 10.0f; static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = std::chrono::nanoseconds(static_cast<nsecs_t>(1e9f / MIN_FPS_FOR_FREQUENT_LAYER)) + 1ms; static constexpr std::chrono::nanoseconds MAX_FREQUENT_LAYER_PERIOD_NS = 150ms; friend class LayerHistoryTestV2; Loading @@ -63,7 +61,7 @@ public: // Records the last requested present time. It also stores information about when // the layer was last updated. If the present time is farther in the future than the // updated time, the updated time is the present time. void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now); void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, bool pendingConfigChange); // Sets an explicit layer vote. This usually comes directly from the application via // ANativeWindow_setFrameRate API Loading Loading @@ -93,11 +91,14 @@ private: struct FrameTimeData { nsecs_t presetTime; // desiredPresentTime, if provided nsecs_t queueTime; // buffer queue time bool pendingConfigChange; }; bool isFrequent(nsecs_t now) const; bool isFrequent(nsecs_t now); bool hasEnoughDataForHeuristic() const; std::optional<float> calculateRefreshRateIfPossible(); std::pair<nsecs_t, bool> calculateAverageFrameTime() const; bool isRefreshRateStable(nsecs_t averageFrameTime, bool missingPresentTime) const; const std::string mName; Loading @@ -109,6 +110,13 @@ private: float mLastReportedRefreshRate = 0.0f; // Used to determine whether a layer should be considered frequent or // not when we don't have enough frames. This member will not be cleared // as part of clearHistory() to remember whether this layer was frequent // or not before we processed touch boost (or anything else that would // clear layer history). bool mLastReportedIsFrequent = true; // Holds information about the layer vote struct { LayerHistory::LayerVoteType type; Loading Loading
services/surfaceflinger/Layer.cpp +9 −2 Original line number Diff line number Diff line Loading @@ -1353,8 +1353,15 @@ void Layer::updateTreeHasFrameRateVote() { // First traverse the tree and count how many layers has votes int layersWithVote = 0; traverseTree([&layersWithVote](Layer* layer) { if (layer->mCurrentState.frameRate.rate > 0 || layer->mCurrentState.frameRate.type == FrameRateCompatibility::NoVote) { const auto layerVotedWithDefaultCompatibility = layer->mCurrentState.frameRate.rate > 0 && layer->mCurrentState.frameRate.type == FrameRateCompatibility::Default; const auto layerVotedWithNoVote = layer->mCurrentState.frameRate.type == FrameRateCompatibility::NoVote; // We do not count layers that are ExactOrMultiple for the same reason // we are allowing touch boost for those layers. See // RefreshRateConfigs::getBestRefreshRate for more details. if (layerVotedWithDefaultCompatibility || layerVotedWithNoVote) { layersWithVote++; } }); Loading
services/surfaceflinger/Scheduler/LayerHistory.h +9 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,8 @@ public: // Sets the display size. Client is responsible for synchronization. virtual void setDisplayArea(uint32_t displayArea) = 0; virtual void setConfigChangePending(bool pending) = 0; // Marks the layer as active, and records the given state to its history. virtual void record(Layer*, nsecs_t presentTime, nsecs_t now) = 0; Loading @@ -78,6 +80,8 @@ public: void setDisplayArea(uint32_t /*displayArea*/) override {} void setConfigChangePending(bool /*pending*/) override {} // Marks the layer as active, and records the given state to its history. void record(Layer*, nsecs_t presentTime, nsecs_t now) override; Loading Loading @@ -134,6 +138,8 @@ public: // Sets the display size. Client is responsible for synchronization. void setDisplayArea(uint32_t displayArea) override { mDisplayArea = displayArea; } void setConfigChangePending(bool pending) override { mConfigChangePending = pending; } // Marks the layer as active, and records the given state to its history. void record(Layer*, nsecs_t presentTime, nsecs_t now) override; Loading Loading @@ -178,6 +184,9 @@ private: // Whether to use priority sent from WindowManager to determine the relevancy of the layer. const bool mUseFrameRatePriority; // Whether a config change is in progress or not std::atomic<bool> mConfigChangePending = false; }; } // namespace impl Loading
services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -103,7 +103,7 @@ void LayerHistoryV2::record(Layer* layer, nsecs_t presentTime, nsecs_t now) { LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer); const auto& info = it->second; info->setLastPresentTime(presentTime, now); info->setLastPresentTime(presentTime, now, mConfigChangePending); // Activate layer if inactive. if (const auto end = activeLayers().end(); it >= end) { Loading
services/surfaceflinger/Scheduler/LayerInfoV2.cpp +65 −36 Original line number Diff line number Diff line Loading @@ -34,12 +34,15 @@ LayerInfoV2::LayerInfoV2(const std::string& name, nsecs_t highRefreshRatePeriod, mDefaultVote(defaultVote), mLayerVote({defaultVote, 0.0f}) {} void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now) { void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, bool pendingConfigChange) { lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0)); mLastUpdatedTime = std::max(lastPresentTime, now); FrameTimeData frameTime = {.presetTime = lastPresentTime, .queueTime = mLastUpdatedTime}; FrameTimeData frameTime = {.presetTime = lastPresentTime, .queueTime = mLastUpdatedTime, .pendingConfigChange = pendingConfigChange}; mFrameTimes.push_back(frameTime); if (mFrameTimes.size() > HISTORY_SIZE) { Loading @@ -47,23 +50,28 @@ void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now) { } } bool LayerInfoV2::isFrequent(nsecs_t now) const { bool LayerInfoV2::isFrequent(nsecs_t now) { mLastReportedIsFrequent = [&] { for (auto it = mFrameTimes.crbegin(); it != mFrameTimes.crend(); ++it) { if (now - it->queueTime >= MAX_FREQUENT_LAYER_PERIOD_NS.count()) { ALOGV("%s infrequent (last frame is %.2fms ago", mName.c_str(), ALOGV("%s infrequent (last frame is %.2fms ago)", mName.c_str(), (now - mFrameTimes.back().queueTime) / 1e6f); return false; } const auto numFrames = std::distance(mFrameTimes.crbegin(), it + 1); if (numFrames >= FREQUENT_LAYER_WINDOW_SIZE) { ALOGV("%s frequent (burst of %zu frames", mName.c_str(), numFrames); ALOGV("%s frequent (burst of %zu frames)", mName.c_str(), numFrames); return true; } } ALOGV("%s infrequent (not enough frames %zu)", mName.c_str(), mFrameTimes.size()); return false; ALOGV("%s %sfrequent (not enough frames %zu)", mName.c_str(), mLastReportedIsFrequent ? "" : "in", mFrameTimes.size()); return mLastReportedIsFrequent; }(); return mLastReportedIsFrequent; } bool LayerInfoV2::hasEnoughDataForHeuristic() const { Loading @@ -80,21 +88,20 @@ bool LayerInfoV2::hasEnoughDataForHeuristic() const { return true; } std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { static constexpr float MARGIN = 1.0f; // 1Hz if (!hasEnoughDataForHeuristic()) { ALOGV("Not enough data"); return std::nullopt; } // Calculate the refresh rate by finding the average delta between frames std::pair<nsecs_t, bool> LayerInfoV2::calculateAverageFrameTime() const { nsecs_t totalPresentTimeDeltas = 0; nsecs_t totalQueueTimeDeltas = 0; auto missingPresentTime = false; bool missingPresentTime = false; int numFrames = 0; for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) { // Ignore frames captured during a config change if (it->pendingConfigChange || (it + 1)->pendingConfigChange) { continue; } totalQueueTimeDeltas += std::max(((it + 1)->queueTime - it->queueTime), mHighRefreshRatePeriod); numFrames++; if (it->presetTime == 0 || (it + 1)->presetTime == 0) { missingPresentTime = true; Loading @@ -105,11 +112,6 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod); } // If there are no presentation timestamps provided we can't calculate the refresh rate if (missingPresentTime && mLastReportedRefreshRate == 0) { return std::nullopt; } // Calculate the average frame time based on presentation timestamps. If those // doesn't exist, we look at the time the buffer was queued only. We can do that only if // we calculated a refresh rate based on presentation timestamps in the past. The reason Loading @@ -117,13 +119,18 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { // when implementing render ahead for specific refresh rates. When hwui no longer provides // presentation timestamps we look at the queue time to see if the current refresh rate still // matches the content. const float averageFrameTime = const auto averageFrameTime = static_cast<float>(missingPresentTime ? totalQueueTimeDeltas : totalPresentTimeDeltas) / (mFrameTimes.size() - 1); numFrames; return {static_cast<nsecs_t>(averageFrameTime), missingPresentTime}; } // Now once we calculated the refresh rate we need to make sure that all the frames we captured // are evenly distributed and we don't calculate the average across some burst of frames. bool LayerInfoV2::isRefreshRateStable(nsecs_t averageFrameTime, bool missingPresentTime) const { for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) { // Ignore frames captured during a config change if (it->pendingConfigChange || (it + 1)->pendingConfigChange) { continue; } const auto presentTimeDeltas = [&] { const auto delta = missingPresentTime ? (it + 1)->queueTime - it->queueTime : (it + 1)->presetTime - it->presetTime; Loading @@ -131,8 +138,30 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { }(); if (std::abs(presentTimeDeltas - averageFrameTime) > 2 * averageFrameTime) { return false; } } return true; } std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { static constexpr float MARGIN = 1.0f; // 1Hz if (!hasEnoughDataForHeuristic()) { ALOGV("Not enough data"); return std::nullopt; } const auto [averageFrameTime, missingPresentTime] = calculateAverageFrameTime(); // If there are no presentation timestamps provided we can't calculate the refresh rate if (missingPresentTime && mLastReportedRefreshRate == 0) { return std::nullopt; } if (!isRefreshRateStable(averageFrameTime, missingPresentTime)) { return std::nullopt; } const auto refreshRate = 1e9f / averageFrameTime; Loading
services/surfaceflinger/Scheduler/LayerInfoV2.h +13 −5 Original line number Diff line number Diff line Loading @@ -47,9 +47,7 @@ class LayerInfoV2 { // is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in // favor of a low refresh rate. static constexpr size_t FREQUENT_LAYER_WINDOW_SIZE = 3; static constexpr float MIN_FPS_FOR_FREQUENT_LAYER = 10.0f; static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = std::chrono::nanoseconds(static_cast<nsecs_t>(1e9f / MIN_FPS_FOR_FREQUENT_LAYER)) + 1ms; static constexpr std::chrono::nanoseconds MAX_FREQUENT_LAYER_PERIOD_NS = 150ms; friend class LayerHistoryTestV2; Loading @@ -63,7 +61,7 @@ public: // Records the last requested present time. It also stores information about when // the layer was last updated. If the present time is farther in the future than the // updated time, the updated time is the present time. void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now); void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, bool pendingConfigChange); // Sets an explicit layer vote. This usually comes directly from the application via // ANativeWindow_setFrameRate API Loading Loading @@ -93,11 +91,14 @@ private: struct FrameTimeData { nsecs_t presetTime; // desiredPresentTime, if provided nsecs_t queueTime; // buffer queue time bool pendingConfigChange; }; bool isFrequent(nsecs_t now) const; bool isFrequent(nsecs_t now); bool hasEnoughDataForHeuristic() const; std::optional<float> calculateRefreshRateIfPossible(); std::pair<nsecs_t, bool> calculateAverageFrameTime() const; bool isRefreshRateStable(nsecs_t averageFrameTime, bool missingPresentTime) const; const std::string mName; Loading @@ -109,6 +110,13 @@ private: float mLastReportedRefreshRate = 0.0f; // Used to determine whether a layer should be considered frequent or // not when we don't have enough frames. This member will not be cleared // as part of clearHistory() to remember whether this layer was frequent // or not before we processed touch boost (or anything else that would // clear layer history). bool mLastReportedIsFrequent = true; // Holds information about the layer vote struct { LayerHistory::LayerVoteType type; Loading