Loading services/surfaceflinger/Layer.h +3 −53 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ #include "LayerVector.h" #include "MonitoredProducer.h" #include "RenderArea.h" #include "Scheduler/LayerInfo.h" #include "Scheduler/Seamlessness.h" #include "SurfaceFlinger.h" #include "SurfaceTracing.h" Loading Loading @@ -141,59 +142,8 @@ public: float radius = 0.0f; }; // FrameRateCompatibility specifies how we should interpret the frame rate associated with // the layer. enum class FrameRateCompatibility { Default, // Layer didn't specify any specific handling strategy Exact, // Layer needs the exact frame rate. ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the // content properly. Any other value will result in a pull down. NoVote, // Layer doesn't have any requirements for the refresh rate and // should not be considered when the display refresh rate is determined. }; // Encapsulates the frame rate and compatibility of the layer. This information will be used // when the display refresh rate is determined. struct FrameRate { using Seamlessness = scheduler::Seamlessness; Fps rate; FrameRateCompatibility type; Seamlessness seamlessness; FrameRate() : rate(0), type(FrameRateCompatibility::Default), seamlessness(Seamlessness::Default) {} FrameRate(Fps rate, FrameRateCompatibility type, Seamlessness seamlessness = Seamlessness::OnlySeamless) : rate(rate), type(type), seamlessness(getSeamlessness(rate, seamlessness)) {} bool operator==(const FrameRate& other) const { return rate.equalsWithMargin(other.rate) && type == other.type && seamlessness == other.seamlessness; } bool operator!=(const FrameRate& other) const { return !(*this == other); } // Convert an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value to a // Layer::FrameRateCompatibility. Logs fatal if the compatibility value is invalid. static FrameRateCompatibility convertCompatibility(int8_t compatibility); static scheduler::Seamlessness convertChangeFrameRateStrategy(int8_t strategy); private: static Seamlessness getSeamlessness(Fps rate, Seamlessness seamlessness) { if (!rate.isValid()) { // Refresh rate of 0 is a special value which should reset the vote to // its default value. return Seamlessness::Default; } return seamlessness; } }; using FrameRate = scheduler::LayerInfo::FrameRate; using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility; struct State { Geometry active_legacy; Loading services/surfaceflinger/Scheduler/LayerHistory.cpp +43 −40 Original line number Diff line number Diff line Loading @@ -39,13 +39,13 @@ namespace android::scheduler { namespace { bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) { bool isLayerActive(const LayerInfo& info, nsecs_t threshold) { // Layers with an explicit vote are always kept active if (layer.getFrameRateForLayerTree().rate.isValid()) { if (info.getSetFrameRateVote().rate.isValid()) { return true; } return layer.isVisible() && info.getLastUpdatedTime() >= threshold; return info.isVisible() && info.getLastUpdatedTime() >= threshold; } bool traceEnabled() { Loading @@ -58,11 +58,7 @@ bool useFrameRatePriority() { return atoi(value); } void trace(const wp<Layer>& weak, const LayerInfo& info, LayerHistory::LayerVoteType type, int fps) { const auto layer = weak.promote(); if (!layer) return; void trace(const LayerInfo& info, LayerHistory::LayerVoteType type, int fps) { const auto traceType = [&](LayerHistory::LayerVoteType checkedType, int value) { ATRACE_INT(info.getTraceTag(checkedType), type == checkedType ? value : 0); }; Loading @@ -75,7 +71,7 @@ void trace(const wp<Layer>& weak, const LayerInfo& info, LayerHistory::LayerVote traceType(LayerHistory::LayerVoteType::Min, 1); traceType(LayerHistory::LayerVoteType::Max, 1); ALOGD("%s: %s @ %d Hz", __FUNCTION__, layer->getName().c_str(), fps); ALOGD("%s: %s @ %d Hz", __FUNCTION__, info.getName().c_str(), fps); } } // namespace Loading @@ -88,11 +84,27 @@ LayerHistory::LayerHistory(const RefreshRateConfigs& refreshRateConfigs) LayerHistory::~LayerHistory() = default; void LayerHistory::registerLayer(Layer* layer, LayerVoteType type) { auto info = std::make_unique<LayerInfo>(layer->getName(), type); auto info = std::make_unique<LayerInfo>(layer->getName(), layer->getOwnerUid(), type); std::lock_guard lock(mLock); mLayerInfos.emplace_back(layer, std::move(info)); } void LayerHistory::deregisterLayer(Layer* layer) { std::lock_guard lock(mLock); const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(), [layer](const auto& pair) { return pair.first == layer; }); LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer); const size_t i = static_cast<size_t>(it - mLayerInfos.begin()); if (i < mActiveLayersEnd) { mActiveLayersEnd--; } const size_t last = mLayerInfos.size() - 1; std::swap(mLayerInfos[i], mLayerInfos[last]); mLayerInfos.erase(mLayerInfos.begin() + static_cast<long>(last)); } void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now, LayerUpdateType updateType) { std::lock_guard lock(mLock); Loading @@ -102,7 +114,15 @@ void LayerHistory::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, updateType, mModeChangePending); const auto layerProps = LayerInfo::LayerProps{ .visible = layer->isVisible(), .bounds = layer->getBounds(), .transform = layer->getTransform(), .setFrameRateVote = layer->getFrameRateForLayerTree(), .frameRateSelectionPriority = layer->getFrameRateSelectionPriority(), }; info->setLastPresentTime(presentTime, now, updateType, mModeChangePending, layerProps); // Activate layer if inactive. if (const auto end = activeLayers().end(); it >= end) { Loading @@ -119,15 +139,10 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { partitionLayers(now); for (const auto& [layer, info] : activeLayers()) { const auto strong = layer.promote(); if (!strong) { continue; } const auto frameRateSelectionPriority = strong->getFrameRateSelectionPriority(); const auto frameRateSelectionPriority = info->getFrameRateSelectionPriority(); const auto layerFocused = Layer::isLayerFocusedBasedOnPriority(frameRateSelectionPriority); ALOGV("%s has priority: %d %s focused", strong->getName().c_str(), frameRateSelectionPriority, layerFocused ? "" : "not"); ALOGV("%s has priority: %d %s focused", info->getName().c_str(), frameRateSelectionPriority, layerFocused ? "" : "not"); const auto vote = info->getRefreshRateVote(now); // Skip NoVote layer as those don't have any requirements Loading @@ -136,18 +151,18 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { } // Compute the layer's position on the screen const Rect bounds = Rect(strong->getBounds()); const ui::Transform transform = strong->getTransform(); const Rect bounds = Rect(info->getBounds()); const ui::Transform transform = info->getTransform(); constexpr bool roundOutwards = true; Rect transformed = transform.transform(bounds, roundOutwards); const float layerArea = transformed.getWidth() * transformed.getHeight(); float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f; summary.push_back({strong->getName(), strong->getOwnerUid(), vote.type, vote.fps, summary.push_back({info->getName(), info->getOwnerUid(), vote.type, vote.fps, vote.seamlessness, weight, layerFocused}); if (CC_UNLIKELY(mTraceEnabled)) { trace(layer, *info, vote.type, vote.fps.getIntValue()); trace(*info, vote.type, vote.fps.getIntValue()); } } Loading @@ -160,11 +175,11 @@ void LayerHistory::partitionLayers(nsecs_t now) { // Collect expired and inactive layers after active layers. size_t i = 0; while (i < mActiveLayersEnd) { auto& [weak, info] = mLayerInfos[i]; if (const auto layer = weak.promote(); layer && isLayerActive(*layer, *info, threshold)) { auto& [layerUnsafe, info] = mLayerInfos[i]; if (isLayerActive(*info, threshold)) { i++; // Set layer vote if set const auto frameRate = layer->getFrameRateForLayerTree(); const auto frameRate = info->getSetFrameRateVote(); const auto voteType = [&]() { switch (frameRate.type) { case Layer::FrameRateCompatibility::Default: Loading @@ -179,7 +194,7 @@ void LayerHistory::partitionLayers(nsecs_t now) { }(); if (frameRate.rate.isValid() || voteType == LayerVoteType::NoVote) { const auto type = layer->isVisible() ? voteType : LayerVoteType::NoVote; const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote; info->setLayerVote({type, frameRate.rate, frameRate.seamlessness}); } else { info->resetLayerVote(); Loading @@ -188,24 +203,12 @@ void LayerHistory::partitionLayers(nsecs_t now) { } if (CC_UNLIKELY(mTraceEnabled)) { trace(weak, *info, LayerHistory::LayerVoteType::NoVote, 0); trace(*info, LayerHistory::LayerVoteType::NoVote, 0); } info->onLayerInactive(now); std::swap(mLayerInfos[i], mLayerInfos[--mActiveLayersEnd]); } // Collect expired layers after inactive layers. size_t end = mLayerInfos.size(); while (i < end) { if (mLayerInfos[i].first.promote()) { i++; } else { std::swap(mLayerInfos[i], mLayerInfos[--end]); } } mLayerInfos.erase(mLayerInfos.begin() + static_cast<long>(end), mLayerInfos.end()); } void LayerHistory::clear() { Loading services/surfaceflinger/Scheduler/LayerHistory.h +3 −1 Original line number Diff line number Diff line Loading @@ -70,13 +70,15 @@ public: Summary summarize(nsecs_t now); void clear(); void deregisterLayer(Layer*); std::string dump() const; private: friend LayerHistoryTest; friend TestableScheduler; using LayerPair = std::pair<wp<Layer>, std::unique_ptr<LayerInfo>>; using LayerPair = std::pair<Layer*, std::unique_ptr<LayerInfo>>; using LayerInfos = std::vector<LayerPair>; struct ActiveLayers { Loading services/surfaceflinger/Scheduler/LayerInfo.cpp +5 −2 Original line number Diff line number Diff line Loading @@ -37,17 +37,20 @@ namespace android::scheduler { const RefreshRateConfigs* LayerInfo::sRefreshRateConfigs = nullptr; bool LayerInfo::sTraceEnabled = false; LayerInfo::LayerInfo(const std::string& name, LayerHistory::LayerVoteType defaultVote) LayerInfo::LayerInfo(const std::string& name, uid_t ownerUid, LayerHistory::LayerVoteType defaultVote) : mName(name), mOwnerUid(ownerUid), mDefaultVote(defaultVote), mLayerVote({defaultVote, Fps(0.0f)}), mRefreshRateHistory(name) {} void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, LayerUpdateType updateType, bool pendingModeChange) { bool pendingModeChange, LayerProps props) { lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0)); mLastUpdatedTime = std::max(lastPresentTime, now); mLayerProps = props; switch (updateType) { case LayerUpdateType::AnimationTX: mLastAnimationTime = std::max(lastPresentTime, now); Loading services/surfaceflinger/Scheduler/LayerInfo.h +80 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #pragma once #include <ui/Transform.h> #include <utils/Timers.h> #include <chrono> Loading Loading @@ -65,22 +66,84 @@ public: Seamlessness seamlessness = Seamlessness::Default; }; // FrameRateCompatibility specifies how we should interpret the frame rate associated with // the layer. enum class FrameRateCompatibility { Default, // Layer didn't specify any specific handling strategy Exact, // Layer needs the exact frame rate. ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the // content properly. Any other value will result in a pull down. NoVote, // Layer doesn't have any requirements for the refresh rate and // should not be considered when the display refresh rate is determined. }; // Encapsulates the frame rate and compatibility of the layer. This information will be used // when the display refresh rate is determined. struct FrameRate { using Seamlessness = scheduler::Seamlessness; Fps rate; FrameRateCompatibility type; Seamlessness seamlessness; FrameRate() : rate(0), type(FrameRateCompatibility::Default), seamlessness(Seamlessness::Default) {} FrameRate(Fps rate, FrameRateCompatibility type, Seamlessness seamlessness = Seamlessness::OnlySeamless) : rate(rate), type(type), seamlessness(getSeamlessness(rate, seamlessness)) {} bool operator==(const FrameRate& other) const { return rate.equalsWithMargin(other.rate) && type == other.type && seamlessness == other.seamlessness; } bool operator!=(const FrameRate& other) const { return !(*this == other); } // Convert an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value to a // Layer::FrameRateCompatibility. Logs fatal if the compatibility value is invalid. static FrameRateCompatibility convertCompatibility(int8_t compatibility); static scheduler::Seamlessness convertChangeFrameRateStrategy(int8_t strategy); private: static Seamlessness getSeamlessness(Fps rate, Seamlessness seamlessness) { if (!rate.isValid()) { // Refresh rate of 0 is a special value which should reset the vote to // its default value. return Seamlessness::Default; } return seamlessness; } }; static void setTraceEnabled(bool enabled) { sTraceEnabled = enabled; } static void setRefreshRateConfigs(const RefreshRateConfigs& refreshRateConfigs) { sRefreshRateConfigs = &refreshRateConfigs; } LayerInfo(const std::string& name, LayerHistory::LayerVoteType defaultVote); LayerInfo(const std::string& name, uid_t ownerUid, LayerHistory::LayerVoteType defaultVote); LayerInfo(const LayerInfo&) = delete; LayerInfo& operator=(const LayerInfo&) = delete; struct LayerProps { bool visible = false; FloatRect bounds; ui::Transform transform; FrameRate setFrameRateVote; int32_t frameRateSelectionPriority = -1; }; // 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, LayerUpdateType updateType, bool pendingModeChange); bool pendingModeChange, LayerProps props); // Sets an explicit layer vote. This usually comes directly from the application via // ANativeWindow_setFrameRate API Loading @@ -94,12 +157,24 @@ public: // Resets the layer vote to its default. void resetLayerVote() { mLayerVote = {mDefaultVote, Fps(0.0f), Seamlessness::Default}; } std::string getName() const { return mName; } uid_t getOwnerUid() const { return mOwnerUid; } LayerVote getRefreshRateVote(nsecs_t now); // Return the last updated time. If the present time is farther in the future than the // updated time, the updated time is the present time. nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; } FrameRate getSetFrameRateVote() const { return mLayerProps.setFrameRateVote; } bool isVisible() const { return mLayerProps.visible; } int32_t getFrameRateSelectionPriority() const { return mLayerProps.frameRateSelectionPriority; } FloatRect getBounds() const { return mLayerProps.bounds; } ui::Transform getTransform() const { return mLayerProps.transform; } // Returns a C string for tracing a vote const char* getTraceTag(LayerHistory::LayerVoteType type) const; Loading Loading @@ -193,6 +268,7 @@ private: bool isFrameTimeValid(const FrameTimeData&) const; const std::string mName; const uid_t mOwnerUid; // Used for sanitizing the heuristic data. If two frames are less than // this period apart from each other they'll be considered as duplicates. Loading @@ -217,6 +293,8 @@ private: static constexpr size_t HISTORY_SIZE = RefreshRateHistory::HISTORY_SIZE; static constexpr std::chrono::nanoseconds HISTORY_DURATION = 1s; LayerProps mLayerProps; RefreshRateHistory mRefreshRateHistory; mutable std::unordered_map<LayerHistory::LayerVoteType, std::string> mTraceTags; Loading Loading
services/surfaceflinger/Layer.h +3 −53 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ #include "LayerVector.h" #include "MonitoredProducer.h" #include "RenderArea.h" #include "Scheduler/LayerInfo.h" #include "Scheduler/Seamlessness.h" #include "SurfaceFlinger.h" #include "SurfaceTracing.h" Loading Loading @@ -141,59 +142,8 @@ public: float radius = 0.0f; }; // FrameRateCompatibility specifies how we should interpret the frame rate associated with // the layer. enum class FrameRateCompatibility { Default, // Layer didn't specify any specific handling strategy Exact, // Layer needs the exact frame rate. ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the // content properly. Any other value will result in a pull down. NoVote, // Layer doesn't have any requirements for the refresh rate and // should not be considered when the display refresh rate is determined. }; // Encapsulates the frame rate and compatibility of the layer. This information will be used // when the display refresh rate is determined. struct FrameRate { using Seamlessness = scheduler::Seamlessness; Fps rate; FrameRateCompatibility type; Seamlessness seamlessness; FrameRate() : rate(0), type(FrameRateCompatibility::Default), seamlessness(Seamlessness::Default) {} FrameRate(Fps rate, FrameRateCompatibility type, Seamlessness seamlessness = Seamlessness::OnlySeamless) : rate(rate), type(type), seamlessness(getSeamlessness(rate, seamlessness)) {} bool operator==(const FrameRate& other) const { return rate.equalsWithMargin(other.rate) && type == other.type && seamlessness == other.seamlessness; } bool operator!=(const FrameRate& other) const { return !(*this == other); } // Convert an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value to a // Layer::FrameRateCompatibility. Logs fatal if the compatibility value is invalid. static FrameRateCompatibility convertCompatibility(int8_t compatibility); static scheduler::Seamlessness convertChangeFrameRateStrategy(int8_t strategy); private: static Seamlessness getSeamlessness(Fps rate, Seamlessness seamlessness) { if (!rate.isValid()) { // Refresh rate of 0 is a special value which should reset the vote to // its default value. return Seamlessness::Default; } return seamlessness; } }; using FrameRate = scheduler::LayerInfo::FrameRate; using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility; struct State { Geometry active_legacy; Loading
services/surfaceflinger/Scheduler/LayerHistory.cpp +43 −40 Original line number Diff line number Diff line Loading @@ -39,13 +39,13 @@ namespace android::scheduler { namespace { bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) { bool isLayerActive(const LayerInfo& info, nsecs_t threshold) { // Layers with an explicit vote are always kept active if (layer.getFrameRateForLayerTree().rate.isValid()) { if (info.getSetFrameRateVote().rate.isValid()) { return true; } return layer.isVisible() && info.getLastUpdatedTime() >= threshold; return info.isVisible() && info.getLastUpdatedTime() >= threshold; } bool traceEnabled() { Loading @@ -58,11 +58,7 @@ bool useFrameRatePriority() { return atoi(value); } void trace(const wp<Layer>& weak, const LayerInfo& info, LayerHistory::LayerVoteType type, int fps) { const auto layer = weak.promote(); if (!layer) return; void trace(const LayerInfo& info, LayerHistory::LayerVoteType type, int fps) { const auto traceType = [&](LayerHistory::LayerVoteType checkedType, int value) { ATRACE_INT(info.getTraceTag(checkedType), type == checkedType ? value : 0); }; Loading @@ -75,7 +71,7 @@ void trace(const wp<Layer>& weak, const LayerInfo& info, LayerHistory::LayerVote traceType(LayerHistory::LayerVoteType::Min, 1); traceType(LayerHistory::LayerVoteType::Max, 1); ALOGD("%s: %s @ %d Hz", __FUNCTION__, layer->getName().c_str(), fps); ALOGD("%s: %s @ %d Hz", __FUNCTION__, info.getName().c_str(), fps); } } // namespace Loading @@ -88,11 +84,27 @@ LayerHistory::LayerHistory(const RefreshRateConfigs& refreshRateConfigs) LayerHistory::~LayerHistory() = default; void LayerHistory::registerLayer(Layer* layer, LayerVoteType type) { auto info = std::make_unique<LayerInfo>(layer->getName(), type); auto info = std::make_unique<LayerInfo>(layer->getName(), layer->getOwnerUid(), type); std::lock_guard lock(mLock); mLayerInfos.emplace_back(layer, std::move(info)); } void LayerHistory::deregisterLayer(Layer* layer) { std::lock_guard lock(mLock); const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(), [layer](const auto& pair) { return pair.first == layer; }); LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer); const size_t i = static_cast<size_t>(it - mLayerInfos.begin()); if (i < mActiveLayersEnd) { mActiveLayersEnd--; } const size_t last = mLayerInfos.size() - 1; std::swap(mLayerInfos[i], mLayerInfos[last]); mLayerInfos.erase(mLayerInfos.begin() + static_cast<long>(last)); } void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now, LayerUpdateType updateType) { std::lock_guard lock(mLock); Loading @@ -102,7 +114,15 @@ void LayerHistory::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, updateType, mModeChangePending); const auto layerProps = LayerInfo::LayerProps{ .visible = layer->isVisible(), .bounds = layer->getBounds(), .transform = layer->getTransform(), .setFrameRateVote = layer->getFrameRateForLayerTree(), .frameRateSelectionPriority = layer->getFrameRateSelectionPriority(), }; info->setLastPresentTime(presentTime, now, updateType, mModeChangePending, layerProps); // Activate layer if inactive. if (const auto end = activeLayers().end(); it >= end) { Loading @@ -119,15 +139,10 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { partitionLayers(now); for (const auto& [layer, info] : activeLayers()) { const auto strong = layer.promote(); if (!strong) { continue; } const auto frameRateSelectionPriority = strong->getFrameRateSelectionPriority(); const auto frameRateSelectionPriority = info->getFrameRateSelectionPriority(); const auto layerFocused = Layer::isLayerFocusedBasedOnPriority(frameRateSelectionPriority); ALOGV("%s has priority: %d %s focused", strong->getName().c_str(), frameRateSelectionPriority, layerFocused ? "" : "not"); ALOGV("%s has priority: %d %s focused", info->getName().c_str(), frameRateSelectionPriority, layerFocused ? "" : "not"); const auto vote = info->getRefreshRateVote(now); // Skip NoVote layer as those don't have any requirements Loading @@ -136,18 +151,18 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { } // Compute the layer's position on the screen const Rect bounds = Rect(strong->getBounds()); const ui::Transform transform = strong->getTransform(); const Rect bounds = Rect(info->getBounds()); const ui::Transform transform = info->getTransform(); constexpr bool roundOutwards = true; Rect transformed = transform.transform(bounds, roundOutwards); const float layerArea = transformed.getWidth() * transformed.getHeight(); float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f; summary.push_back({strong->getName(), strong->getOwnerUid(), vote.type, vote.fps, summary.push_back({info->getName(), info->getOwnerUid(), vote.type, vote.fps, vote.seamlessness, weight, layerFocused}); if (CC_UNLIKELY(mTraceEnabled)) { trace(layer, *info, vote.type, vote.fps.getIntValue()); trace(*info, vote.type, vote.fps.getIntValue()); } } Loading @@ -160,11 +175,11 @@ void LayerHistory::partitionLayers(nsecs_t now) { // Collect expired and inactive layers after active layers. size_t i = 0; while (i < mActiveLayersEnd) { auto& [weak, info] = mLayerInfos[i]; if (const auto layer = weak.promote(); layer && isLayerActive(*layer, *info, threshold)) { auto& [layerUnsafe, info] = mLayerInfos[i]; if (isLayerActive(*info, threshold)) { i++; // Set layer vote if set const auto frameRate = layer->getFrameRateForLayerTree(); const auto frameRate = info->getSetFrameRateVote(); const auto voteType = [&]() { switch (frameRate.type) { case Layer::FrameRateCompatibility::Default: Loading @@ -179,7 +194,7 @@ void LayerHistory::partitionLayers(nsecs_t now) { }(); if (frameRate.rate.isValid() || voteType == LayerVoteType::NoVote) { const auto type = layer->isVisible() ? voteType : LayerVoteType::NoVote; const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote; info->setLayerVote({type, frameRate.rate, frameRate.seamlessness}); } else { info->resetLayerVote(); Loading @@ -188,24 +203,12 @@ void LayerHistory::partitionLayers(nsecs_t now) { } if (CC_UNLIKELY(mTraceEnabled)) { trace(weak, *info, LayerHistory::LayerVoteType::NoVote, 0); trace(*info, LayerHistory::LayerVoteType::NoVote, 0); } info->onLayerInactive(now); std::swap(mLayerInfos[i], mLayerInfos[--mActiveLayersEnd]); } // Collect expired layers after inactive layers. size_t end = mLayerInfos.size(); while (i < end) { if (mLayerInfos[i].first.promote()) { i++; } else { std::swap(mLayerInfos[i], mLayerInfos[--end]); } } mLayerInfos.erase(mLayerInfos.begin() + static_cast<long>(end), mLayerInfos.end()); } void LayerHistory::clear() { Loading
services/surfaceflinger/Scheduler/LayerHistory.h +3 −1 Original line number Diff line number Diff line Loading @@ -70,13 +70,15 @@ public: Summary summarize(nsecs_t now); void clear(); void deregisterLayer(Layer*); std::string dump() const; private: friend LayerHistoryTest; friend TestableScheduler; using LayerPair = std::pair<wp<Layer>, std::unique_ptr<LayerInfo>>; using LayerPair = std::pair<Layer*, std::unique_ptr<LayerInfo>>; using LayerInfos = std::vector<LayerPair>; struct ActiveLayers { Loading
services/surfaceflinger/Scheduler/LayerInfo.cpp +5 −2 Original line number Diff line number Diff line Loading @@ -37,17 +37,20 @@ namespace android::scheduler { const RefreshRateConfigs* LayerInfo::sRefreshRateConfigs = nullptr; bool LayerInfo::sTraceEnabled = false; LayerInfo::LayerInfo(const std::string& name, LayerHistory::LayerVoteType defaultVote) LayerInfo::LayerInfo(const std::string& name, uid_t ownerUid, LayerHistory::LayerVoteType defaultVote) : mName(name), mOwnerUid(ownerUid), mDefaultVote(defaultVote), mLayerVote({defaultVote, Fps(0.0f)}), mRefreshRateHistory(name) {} void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, LayerUpdateType updateType, bool pendingModeChange) { bool pendingModeChange, LayerProps props) { lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0)); mLastUpdatedTime = std::max(lastPresentTime, now); mLayerProps = props; switch (updateType) { case LayerUpdateType::AnimationTX: mLastAnimationTime = std::max(lastPresentTime, now); Loading
services/surfaceflinger/Scheduler/LayerInfo.h +80 −2 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #pragma once #include <ui/Transform.h> #include <utils/Timers.h> #include <chrono> Loading Loading @@ -65,22 +66,84 @@ public: Seamlessness seamlessness = Seamlessness::Default; }; // FrameRateCompatibility specifies how we should interpret the frame rate associated with // the layer. enum class FrameRateCompatibility { Default, // Layer didn't specify any specific handling strategy Exact, // Layer needs the exact frame rate. ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the // content properly. Any other value will result in a pull down. NoVote, // Layer doesn't have any requirements for the refresh rate and // should not be considered when the display refresh rate is determined. }; // Encapsulates the frame rate and compatibility of the layer. This information will be used // when the display refresh rate is determined. struct FrameRate { using Seamlessness = scheduler::Seamlessness; Fps rate; FrameRateCompatibility type; Seamlessness seamlessness; FrameRate() : rate(0), type(FrameRateCompatibility::Default), seamlessness(Seamlessness::Default) {} FrameRate(Fps rate, FrameRateCompatibility type, Seamlessness seamlessness = Seamlessness::OnlySeamless) : rate(rate), type(type), seamlessness(getSeamlessness(rate, seamlessness)) {} bool operator==(const FrameRate& other) const { return rate.equalsWithMargin(other.rate) && type == other.type && seamlessness == other.seamlessness; } bool operator!=(const FrameRate& other) const { return !(*this == other); } // Convert an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value to a // Layer::FrameRateCompatibility. Logs fatal if the compatibility value is invalid. static FrameRateCompatibility convertCompatibility(int8_t compatibility); static scheduler::Seamlessness convertChangeFrameRateStrategy(int8_t strategy); private: static Seamlessness getSeamlessness(Fps rate, Seamlessness seamlessness) { if (!rate.isValid()) { // Refresh rate of 0 is a special value which should reset the vote to // its default value. return Seamlessness::Default; } return seamlessness; } }; static void setTraceEnabled(bool enabled) { sTraceEnabled = enabled; } static void setRefreshRateConfigs(const RefreshRateConfigs& refreshRateConfigs) { sRefreshRateConfigs = &refreshRateConfigs; } LayerInfo(const std::string& name, LayerHistory::LayerVoteType defaultVote); LayerInfo(const std::string& name, uid_t ownerUid, LayerHistory::LayerVoteType defaultVote); LayerInfo(const LayerInfo&) = delete; LayerInfo& operator=(const LayerInfo&) = delete; struct LayerProps { bool visible = false; FloatRect bounds; ui::Transform transform; FrameRate setFrameRateVote; int32_t frameRateSelectionPriority = -1; }; // 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, LayerUpdateType updateType, bool pendingModeChange); bool pendingModeChange, LayerProps props); // Sets an explicit layer vote. This usually comes directly from the application via // ANativeWindow_setFrameRate API Loading @@ -94,12 +157,24 @@ public: // Resets the layer vote to its default. void resetLayerVote() { mLayerVote = {mDefaultVote, Fps(0.0f), Seamlessness::Default}; } std::string getName() const { return mName; } uid_t getOwnerUid() const { return mOwnerUid; } LayerVote getRefreshRateVote(nsecs_t now); // Return the last updated time. If the present time is farther in the future than the // updated time, the updated time is the present time. nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; } FrameRate getSetFrameRateVote() const { return mLayerProps.setFrameRateVote; } bool isVisible() const { return mLayerProps.visible; } int32_t getFrameRateSelectionPriority() const { return mLayerProps.frameRateSelectionPriority; } FloatRect getBounds() const { return mLayerProps.bounds; } ui::Transform getTransform() const { return mLayerProps.transform; } // Returns a C string for tracing a vote const char* getTraceTag(LayerHistory::LayerVoteType type) const; Loading Loading @@ -193,6 +268,7 @@ private: bool isFrameTimeValid(const FrameTimeData&) const; const std::string mName; const uid_t mOwnerUid; // Used for sanitizing the heuristic data. If two frames are less than // this period apart from each other they'll be considered as duplicates. Loading @@ -217,6 +293,8 @@ private: static constexpr size_t HISTORY_SIZE = RefreshRateHistory::HISTORY_SIZE; static constexpr std::chrono::nanoseconds HISTORY_DURATION = 1s; LayerProps mLayerProps; RefreshRateHistory mRefreshRateHistory; mutable std::unordered_map<LayerHistory::LayerVoteType, std::string> mTraceTags; Loading