SF: remove wp<Layer> from LayerHistory
wp::promote has a significant performace impact. Instead we maintain
a copy of the relevant layer information in LayerInfo.
This shows reduction in simpleperf for the main thread
3.07% -> 0.81%
Test: simpleperf for PIP + Notification shade expansion
Test: atest SetFrameRateTest
Bug: 169873384
Change-Id: Ib1414a2db73a4c30a26379a0ba8ba9e639f920ce
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index ea92ad8..f4bc2a1 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -39,13 +39,13 @@
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() {
@@ -58,11 +58,7 @@
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);
};
@@ -75,7 +71,7 @@
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
@@ -88,11 +84,27 @@
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);
@@ -102,7 +114,15 @@
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) {
@@ -119,15 +139,10 @@
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
@@ -136,18 +151,18 @@
}
// 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());
}
}
@@ -160,11 +175,11 @@
// 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:
@@ -179,7 +194,7 @@
}();
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();
@@ -188,24 +203,12 @@
}
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() {
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 05ecc70..82f6c39 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -70,13 +70,15 @@
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 {
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 4b4cdae..3630ad8 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -37,17 +37,20 @@
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);
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 40c0214..ba03c89 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -16,6 +16,7 @@
#pragma once
+#include <ui/Transform.h>
#include <utils/Timers.h>
#include <chrono>
@@ -65,22 +66,84 @@
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
@@ -94,12 +157,24 @@
// 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;
@@ -193,6 +268,7 @@
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.
@@ -217,6 +293,8 @@
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;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 4edbdd2..8426737 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -580,6 +580,12 @@
mLayerHistory->registerLayer(layer, voteType);
}
+void Scheduler::deregisterLayer(Layer* layer) {
+ if (mLayerHistory) {
+ mLayerHistory->deregisterLayer(layer);
+ }
+}
+
void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime,
LayerHistory::LayerUpdateType updateType) {
if (mLayerHistory) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 0e9eba7..d4932e7 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -129,6 +129,7 @@
void registerLayer(Layer*);
void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType);
void setModeChangePending(bool pending);
+ void deregisterLayer(Layer*);
// Detects content using layer history, and selects a matching refresh rate.
void chooseRefreshRateForContent();