Loading services/surfaceflinger/Scheduler/LayerHistory.h +9 −0 Original line number Original line Diff line number Diff line Loading @@ -52,6 +52,8 @@ public: // Sets the display size. Client is responsible for synchronization. // Sets the display size. Client is responsible for synchronization. virtual void setDisplayArea(uint32_t displayArea) = 0; 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. // Marks the layer as active, and records the given state to its history. virtual void record(Layer*, nsecs_t presentTime, nsecs_t now) = 0; virtual void record(Layer*, nsecs_t presentTime, nsecs_t now) = 0; Loading @@ -78,6 +80,8 @@ public: void setDisplayArea(uint32_t /*displayArea*/) override {} void setDisplayArea(uint32_t /*displayArea*/) override {} void setConfigChangePending(bool /*pending*/) override {} // Marks the layer as active, and records the given state to its history. // Marks the layer as active, and records the given state to its history. void record(Layer*, nsecs_t presentTime, nsecs_t now) override; 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. // Sets the display size. Client is responsible for synchronization. void setDisplayArea(uint32_t displayArea) override { mDisplayArea = displayArea; } 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. // Marks the layer as active, and records the given state to its history. void record(Layer*, nsecs_t presentTime, nsecs_t now) override; 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. // Whether to use priority sent from WindowManager to determine the relevancy of the layer. const bool mUseFrameRatePriority; const bool mUseFrameRatePriority; // Whether a config change is in progress or not std::atomic<bool> mConfigChangePending = false; }; }; } // namespace impl } // namespace impl Loading services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +1 −1 Original line number Original line 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); LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer); const auto& info = it->second; const auto& info = it->second; info->setLastPresentTime(presentTime, now); info->setLastPresentTime(presentTime, now, mConfigChangePending); // Activate layer if inactive. // Activate layer if inactive. if (const auto end = activeLayers().end(); it >= end) { if (const auto end = activeLayers().end(); it >= end) { Loading services/surfaceflinger/Scheduler/LayerInfoV2.cpp +46 −22 Original line number Original line Diff line number Diff line Loading @@ -34,12 +34,15 @@ LayerInfoV2::LayerInfoV2(const std::string& name, nsecs_t highRefreshRatePeriod, mDefaultVote(defaultVote), mDefaultVote(defaultVote), mLayerVote({defaultVote, 0.0f}) {} 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)); lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0)); mLastUpdatedTime = std::max(lastPresentTime, now); mLastUpdatedTime = std::max(lastPresentTime, now); FrameTimeData frameTime = {.presetTime = lastPresentTime, .queueTime = mLastUpdatedTime}; FrameTimeData frameTime = {.presetTime = lastPresentTime, .queueTime = mLastUpdatedTime, .pendingConfigChange = pendingConfigChange}; mFrameTimes.push_back(frameTime); mFrameTimes.push_back(frameTime); if (mFrameTimes.size() > HISTORY_SIZE) { if (mFrameTimes.size() > HISTORY_SIZE) { Loading Loading @@ -80,21 +83,20 @@ bool LayerInfoV2::hasEnoughDataForHeuristic() const { return true; return true; } } std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { std::pair<nsecs_t, bool> LayerInfoV2::calculateAverageFrameTime() const { 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 nsecs_t totalPresentTimeDeltas = 0; nsecs_t totalPresentTimeDeltas = 0; nsecs_t totalQueueTimeDeltas = 0; nsecs_t totalQueueTimeDeltas = 0; auto missingPresentTime = false; bool missingPresentTime = false; int numFrames = 0; for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) { 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 += totalQueueTimeDeltas += std::max(((it + 1)->queueTime - it->queueTime), mHighRefreshRatePeriod); std::max(((it + 1)->queueTime - it->queueTime), mHighRefreshRatePeriod); numFrames++; if (it->presetTime == 0 || (it + 1)->presetTime == 0) { if (it->presetTime == 0 || (it + 1)->presetTime == 0) { missingPresentTime = true; missingPresentTime = true; Loading @@ -105,11 +107,6 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod); 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 // 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 // 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 // we calculated a refresh rate based on presentation timestamps in the past. The reason Loading @@ -117,13 +114,18 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { // when implementing render ahead for specific refresh rates. When hwui no longer provides // 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 // presentation timestamps we look at the queue time to see if the current refresh rate still // matches the content. // matches the content. const float averageFrameTime = const auto averageFrameTime = static_cast<float>(missingPresentTime ? totalQueueTimeDeltas : totalPresentTimeDeltas) / 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 bool LayerInfoV2::isRefreshRateStable(nsecs_t averageFrameTime, bool missingPresentTime) const { // are evenly distributed and we don't calculate the average across some burst of frames. for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) { 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 presentTimeDeltas = [&] { const auto delta = missingPresentTime ? (it + 1)->queueTime - it->queueTime const auto delta = missingPresentTime ? (it + 1)->queueTime - it->queueTime : (it + 1)->presetTime - it->presetTime; : (it + 1)->presetTime - it->presetTime; Loading @@ -131,8 +133,30 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { }(); }(); if (std::abs(presentTimeDeltas - averageFrameTime) > 2 * averageFrameTime) { 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; 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; const auto refreshRate = 1e9f / averageFrameTime; Loading services/surfaceflinger/Scheduler/LayerInfoV2.h +4 −1 Original line number Original line Diff line number Diff line Loading @@ -63,7 +63,7 @@ public: // Records the last requested present time. It also stores information about when // 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 // 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. // 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 // Sets an explicit layer vote. This usually comes directly from the application via // ANativeWindow_setFrameRate API // ANativeWindow_setFrameRate API Loading Loading @@ -93,11 +93,14 @@ private: struct FrameTimeData { struct FrameTimeData { nsecs_t presetTime; // desiredPresentTime, if provided nsecs_t presetTime; // desiredPresentTime, if provided nsecs_t queueTime; // buffer queue time nsecs_t queueTime; // buffer queue time bool pendingConfigChange; }; }; bool isFrequent(nsecs_t now) const; bool isFrequent(nsecs_t now) const; bool hasEnoughDataForHeuristic() const; bool hasEnoughDataForHeuristic() const; std::optional<float> calculateRefreshRateIfPossible(); std::optional<float> calculateRefreshRateIfPossible(); std::pair<nsecs_t, bool> calculateAverageFrameTime() const; bool isRefreshRateStable(nsecs_t averageFrameTime, bool missingPresentTime) const; const std::string mName; const std::string mName; Loading services/surfaceflinger/Scheduler/Scheduler.cpp +6 −0 Original line number Original line Diff line number Diff line Loading @@ -423,6 +423,12 @@ void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime) { } } } } void Scheduler::setConfigChangePending(bool pending) { if (mLayerHistory) { mLayerHistory->setConfigChangePending(pending); } } void Scheduler::chooseRefreshRateForContent() { void Scheduler::chooseRefreshRateForContent() { if (!mLayerHistory) return; if (!mLayerHistory) return; Loading Loading
services/surfaceflinger/Scheduler/LayerHistory.h +9 −0 Original line number Original line Diff line number Diff line Loading @@ -52,6 +52,8 @@ public: // Sets the display size. Client is responsible for synchronization. // Sets the display size. Client is responsible for synchronization. virtual void setDisplayArea(uint32_t displayArea) = 0; 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. // Marks the layer as active, and records the given state to its history. virtual void record(Layer*, nsecs_t presentTime, nsecs_t now) = 0; virtual void record(Layer*, nsecs_t presentTime, nsecs_t now) = 0; Loading @@ -78,6 +80,8 @@ public: void setDisplayArea(uint32_t /*displayArea*/) override {} void setDisplayArea(uint32_t /*displayArea*/) override {} void setConfigChangePending(bool /*pending*/) override {} // Marks the layer as active, and records the given state to its history. // Marks the layer as active, and records the given state to its history. void record(Layer*, nsecs_t presentTime, nsecs_t now) override; 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. // Sets the display size. Client is responsible for synchronization. void setDisplayArea(uint32_t displayArea) override { mDisplayArea = displayArea; } 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. // Marks the layer as active, and records the given state to its history. void record(Layer*, nsecs_t presentTime, nsecs_t now) override; 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. // Whether to use priority sent from WindowManager to determine the relevancy of the layer. const bool mUseFrameRatePriority; const bool mUseFrameRatePriority; // Whether a config change is in progress or not std::atomic<bool> mConfigChangePending = false; }; }; } // namespace impl } // namespace impl Loading
services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +1 −1 Original line number Original line 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); LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer); const auto& info = it->second; const auto& info = it->second; info->setLastPresentTime(presentTime, now); info->setLastPresentTime(presentTime, now, mConfigChangePending); // Activate layer if inactive. // Activate layer if inactive. if (const auto end = activeLayers().end(); it >= end) { if (const auto end = activeLayers().end(); it >= end) { Loading
services/surfaceflinger/Scheduler/LayerInfoV2.cpp +46 −22 Original line number Original line Diff line number Diff line Loading @@ -34,12 +34,15 @@ LayerInfoV2::LayerInfoV2(const std::string& name, nsecs_t highRefreshRatePeriod, mDefaultVote(defaultVote), mDefaultVote(defaultVote), mLayerVote({defaultVote, 0.0f}) {} 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)); lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0)); mLastUpdatedTime = std::max(lastPresentTime, now); mLastUpdatedTime = std::max(lastPresentTime, now); FrameTimeData frameTime = {.presetTime = lastPresentTime, .queueTime = mLastUpdatedTime}; FrameTimeData frameTime = {.presetTime = lastPresentTime, .queueTime = mLastUpdatedTime, .pendingConfigChange = pendingConfigChange}; mFrameTimes.push_back(frameTime); mFrameTimes.push_back(frameTime); if (mFrameTimes.size() > HISTORY_SIZE) { if (mFrameTimes.size() > HISTORY_SIZE) { Loading Loading @@ -80,21 +83,20 @@ bool LayerInfoV2::hasEnoughDataForHeuristic() const { return true; return true; } } std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { std::pair<nsecs_t, bool> LayerInfoV2::calculateAverageFrameTime() const { 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 nsecs_t totalPresentTimeDeltas = 0; nsecs_t totalPresentTimeDeltas = 0; nsecs_t totalQueueTimeDeltas = 0; nsecs_t totalQueueTimeDeltas = 0; auto missingPresentTime = false; bool missingPresentTime = false; int numFrames = 0; for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) { 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 += totalQueueTimeDeltas += std::max(((it + 1)->queueTime - it->queueTime), mHighRefreshRatePeriod); std::max(((it + 1)->queueTime - it->queueTime), mHighRefreshRatePeriod); numFrames++; if (it->presetTime == 0 || (it + 1)->presetTime == 0) { if (it->presetTime == 0 || (it + 1)->presetTime == 0) { missingPresentTime = true; missingPresentTime = true; Loading @@ -105,11 +107,6 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod); 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 // 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 // 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 // we calculated a refresh rate based on presentation timestamps in the past. The reason Loading @@ -117,13 +114,18 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { // when implementing render ahead for specific refresh rates. When hwui no longer provides // 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 // presentation timestamps we look at the queue time to see if the current refresh rate still // matches the content. // matches the content. const float averageFrameTime = const auto averageFrameTime = static_cast<float>(missingPresentTime ? totalQueueTimeDeltas : totalPresentTimeDeltas) / 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 bool LayerInfoV2::isRefreshRateStable(nsecs_t averageFrameTime, bool missingPresentTime) const { // are evenly distributed and we don't calculate the average across some burst of frames. for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) { 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 presentTimeDeltas = [&] { const auto delta = missingPresentTime ? (it + 1)->queueTime - it->queueTime const auto delta = missingPresentTime ? (it + 1)->queueTime - it->queueTime : (it + 1)->presetTime - it->presetTime; : (it + 1)->presetTime - it->presetTime; Loading @@ -131,8 +133,30 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() { }(); }(); if (std::abs(presentTimeDeltas - averageFrameTime) > 2 * averageFrameTime) { 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; 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; const auto refreshRate = 1e9f / averageFrameTime; Loading
services/surfaceflinger/Scheduler/LayerInfoV2.h +4 −1 Original line number Original line Diff line number Diff line Loading @@ -63,7 +63,7 @@ public: // Records the last requested present time. It also stores information about when // 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 // 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. // 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 // Sets an explicit layer vote. This usually comes directly from the application via // ANativeWindow_setFrameRate API // ANativeWindow_setFrameRate API Loading Loading @@ -93,11 +93,14 @@ private: struct FrameTimeData { struct FrameTimeData { nsecs_t presetTime; // desiredPresentTime, if provided nsecs_t presetTime; // desiredPresentTime, if provided nsecs_t queueTime; // buffer queue time nsecs_t queueTime; // buffer queue time bool pendingConfigChange; }; }; bool isFrequent(nsecs_t now) const; bool isFrequent(nsecs_t now) const; bool hasEnoughDataForHeuristic() const; bool hasEnoughDataForHeuristic() const; std::optional<float> calculateRefreshRateIfPossible(); std::optional<float> calculateRefreshRateIfPossible(); std::pair<nsecs_t, bool> calculateAverageFrameTime() const; bool isRefreshRateStable(nsecs_t averageFrameTime, bool missingPresentTime) const; const std::string mName; const std::string mName; Loading
services/surfaceflinger/Scheduler/Scheduler.cpp +6 −0 Original line number Original line Diff line number Diff line Loading @@ -423,6 +423,12 @@ void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime) { } } } } void Scheduler::setConfigChangePending(bool pending) { if (mLayerHistory) { mLayerHistory->setConfigChangePending(pending); } } void Scheduler::chooseRefreshRateForContent() { void Scheduler::chooseRefreshRateForContent() { if (!mLayerHistory) return; if (!mLayerHistory) return; Loading