SF: Short-circuit scheduler content detection
Avoid registering, recording, partitioning, and transforming layers
for content detection in the scheduler if there is a single refresh
rate config.
Dump content detection version, and layer history stats.
Bug: 158780872
Test: No layer history on crosshatch, ARC, etc.
Test: dumpsys SurfaceFlinger --vsync
Test: libsurfaceflinger_unittest
Change-Id: Ia23a35cd6aa0cb117b19c98f5d0af8c14836430e
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 2925109..cf753a2 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -20,6 +20,7 @@
#include "LayerHistory.h"
+#include <android-base/stringprintf.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <utils/Timers.h>
@@ -180,4 +181,11 @@
mActiveLayersEnd = 0;
}
+
+std::string LayerHistory::dump() const {
+ std::lock_guard lock(mLock);
+ return base::StringPrintf("LayerHistory{size=%zu, active=%zu}", mLayerInfos.size(),
+ mActiveLayersEnd);
+}
+
} // namespace android::scheduler::impl
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 228b8a0..128699b 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -22,6 +22,7 @@
#include <memory>
#include <mutex>
+#include <string>
#include <utility>
#include <vector>
@@ -71,6 +72,7 @@
virtual Summary summarize(nsecs_t now) = 0;
virtual void clear() = 0;
+ virtual std::string dump() const = 0;
};
namespace impl {
@@ -97,6 +99,7 @@
android::scheduler::LayerHistory::Summary summarize(nsecs_t now) override;
void clear() override;
+ std::string dump() const override;
private:
friend class android::scheduler::LayerHistoryTest;
@@ -155,6 +158,7 @@
android::scheduler::LayerHistory::Summary summarize(nsecs_t /*now*/) override;
void clear() override;
+ std::string dump() const override;
private:
friend android::scheduler::LayerHistoryTestV2;
diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
index ee612b0..e42c5cf 100644
--- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
@@ -20,6 +20,7 @@
#include "LayerHistory.h"
+#include <android-base/stringprintf.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <utils/Timers.h>
@@ -31,9 +32,8 @@
#include <utility>
#include "../Layer.h"
-#include "SchedulerUtils.h"
-
#include "LayerInfoV2.h"
+#include "SchedulerUtils.h"
namespace android::scheduler::impl {
@@ -213,4 +213,10 @@
}
}
+std::string LayerHistoryV2::dump() const {
+ std::lock_guard lock(mLock);
+ return base::StringPrintf("LayerHistoryV2{size=%zu, active=%zu}", mLayerInfos.size(),
+ mActiveLayersEnd);
+}
+
} // namespace android::scheduler::impl
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 8a51b85..4ee7ff3 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -273,6 +273,11 @@
RefreshRateConfigs(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
HwcConfigIndexType currentConfigId);
+ // Returns whether switching configs (refresh rate or resolution) is possible.
+ // TODO(b/158780872): Consider HAL support, and skip frame rate detection if the configs only
+ // differ in resolution.
+ bool canSwitch() const { return mRefreshRates.size() > 1; }
+
// Class to enumerate options around toggling the kernel timer on and off. We have an option
// for no change to avoid extra calls to kernel.
enum class KernelIdleTimerAction {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 5c0ba01..ab63d64 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -61,6 +61,7 @@
} while (false)
namespace android {
+namespace {
std::unique_ptr<DispSync> createDispSync(bool supportKernelTimer) {
// TODO (140302863) remove this and use the vsync_reactor system.
@@ -97,25 +98,27 @@
}
}
+const char* toContentDetectionString(bool useContentDetection, bool useContentDetectionV2) {
+ if (!useContentDetection) return "off";
+ return useContentDetectionV2 ? "V2" : "V1";
+}
+
+} // namespace
+
Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
- const scheduler::RefreshRateConfigs& refreshRateConfig,
+ const scheduler::RefreshRateConfigs& refreshRateConfigs,
ISchedulerCallback& schedulerCallback, bool useContentDetectionV2,
bool useContentDetection)
: mSupportKernelTimer(sysprop::support_kernel_idle_timer(false)),
mPrimaryDispSync(createDispSync(mSupportKernelTimer)),
mEventControlThread(new impl::EventControlThread(std::move(function))),
+ mLayerHistory(createLayerHistory(refreshRateConfigs, useContentDetectionV2)),
mSchedulerCallback(schedulerCallback),
- mRefreshRateConfigs(refreshRateConfig),
+ mRefreshRateConfigs(refreshRateConfigs),
mUseContentDetection(useContentDetection),
mUseContentDetectionV2(useContentDetectionV2) {
using namespace sysprop;
- if (mUseContentDetectionV2) {
- mLayerHistory = std::make_unique<scheduler::impl::LayerHistoryV2>(refreshRateConfig);
- } else {
- mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
- }
-
const int setIdleTimerMs = property_get_int32("debug.sf.set_idle_timer_ms", 0);
if (const auto millis = setIdleTimerMs ? setIdleTimerMs : set_idle_timer_ms(0); millis > 0) {
@@ -149,11 +152,13 @@
Scheduler::Scheduler(std::unique_ptr<DispSync> primaryDispSync,
std::unique_ptr<EventControlThread> eventControlThread,
const scheduler::RefreshRateConfigs& configs,
- ISchedulerCallback& schedulerCallback, bool useContentDetectionV2,
+ ISchedulerCallback& schedulerCallback,
+ std::unique_ptr<LayerHistory> layerHistory, bool useContentDetectionV2,
bool useContentDetection)
: mSupportKernelTimer(false),
mPrimaryDispSync(std::move(primaryDispSync)),
mEventControlThread(std::move(eventControlThread)),
+ mLayerHistory(std::move(layerHistory)),
mSchedulerCallback(schedulerCallback),
mRefreshRateConfigs(configs),
mUseContentDetection(useContentDetection),
@@ -166,6 +171,17 @@
mIdleTimer.reset();
}
+std::unique_ptr<LayerHistory> Scheduler::createLayerHistory(
+ const scheduler::RefreshRateConfigs& configs, bool useContentDetectionV2) {
+ if (!configs.canSwitch()) return nullptr;
+
+ if (useContentDetectionV2) {
+ return std::make_unique<scheduler::impl::LayerHistoryV2>(configs);
+ }
+
+ return std::make_unique<scheduler::impl::LayerHistory>();
+}
+
DispSync& Scheduler::getPrimaryDispSync() {
return *mPrimaryDispSync;
}
@@ -499,16 +515,7 @@
}
void Scheduler::notifyTouchEvent() {
- if (!mTouchTimer) return;
-
- // Touch event will boost the refresh rate to performance.
- // Clear Layer History to get fresh FPS detection.
- // NOTE: Instead of checking all the layers, we should be checking the layer
- // that is currently on top. b/142507166 will give us this capability.
- std::lock_guard<std::mutex> lock(mFeatureStateLock);
- if (mLayerHistory) {
- // Layer History will be cleared based on RefreshRateConfigs::getBestRefreshRate
-
+ if (mTouchTimer) {
mTouchTimer->reset();
if (mSupportKernelTimer && mIdleTimer) {
@@ -564,8 +571,14 @@
void Scheduler::touchTimerCallback(TimerState state) {
const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive;
+ // Touch event will boost the refresh rate to performance.
+ // Clear layer history to get fresh FPS detection.
+ // NOTE: Instead of checking all the layers, we should be checking the layer
+ // that is currently on top. b/142507166 will give us this capability.
if (handleTimerStateChanged(&mFeatures.touch, touch)) {
- mLayerHistory->clear();
+ if (mLayerHistory) {
+ mLayerHistory->clear();
+ }
}
ATRACE_INT("TouchState", static_cast<int>(touch));
}
@@ -577,14 +590,13 @@
void Scheduler::dump(std::string& result) const {
using base::StringAppendF;
- const char* const states[] = {"off", "on"};
- StringAppendF(&result, "+ Idle timer: %s\n",
- mIdleTimer ? mIdleTimer->dump().c_str() : states[0]);
+ StringAppendF(&result, "+ Idle timer: %s\n", mIdleTimer ? mIdleTimer->dump().c_str() : "off");
StringAppendF(&result, "+ Touch timer: %s\n",
- mTouchTimer ? mTouchTimer->dump().c_str() : states[0]);
- StringAppendF(&result, "+ Use content detection: %s\n\n",
- sysprop::use_content_detection_for_refresh_rate(false) ? "on" : "off");
+ mTouchTimer ? mTouchTimer->dump().c_str() : "off");
+ StringAppendF(&result, "+ Content detection: %s %s\n\n",
+ toContentDetectionString(mUseContentDetection, mUseContentDetectionV2),
+ mLayerHistory ? mLayerHistory->dump().c_str() : "(no layer history)");
}
template <class T>
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 730ea8f..5fee4b4 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -174,8 +174,11 @@
// Used by tests to inject mocks.
Scheduler(std::unique_ptr<DispSync>, std::unique_ptr<EventControlThread>,
- const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback,
- bool useContentDetectionV2, bool useContentDetection);
+ const scheduler::RefreshRateConfigs&, ISchedulerCallback&,
+ std::unique_ptr<LayerHistory>, bool useContentDetectionV2, bool useContentDetection);
+
+ static std::unique_ptr<LayerHistory> createLayerHistory(const scheduler::RefreshRateConfigs&,
+ bool useContentDetectionV2);
std::unique_ptr<VSyncSource> makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs);
@@ -231,7 +234,7 @@
std::unique_ptr<EventControlThread> mEventControlThread;
// Used to choose refresh rate if content detection is enabled.
- std::unique_ptr<LayerHistory> mLayerHistory;
+ const std::unique_ptr<LayerHistory> mLayerHistory;
// Timer that records time between requests for next vsync.
std::optional<scheduler::OneShotTimer> mIdleTimer;