summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Ram Indani <ramindani@google.com> 2025-03-20 12:47:43 -0700
committer Android (Google) Code Review <android-gerrit@google.com> 2025-03-20 12:47:43 -0700
commitb1e7d3cfe6c857e94400094bbf7421de50e432aa (patch)
tree7d0a9c395767fab7a6789eba1109ef584c929a76
parentde365a6c1bfd64d2e9ef9da49e30f3565ecaf599 (diff)
parent70d21c0b993a26ea6dffa6afc002beab3efd0d95 (diff)
Merge "[SF] Backdoor to update the WorkDuration" into main
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.cpp34
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.h24
-rw-r--r--services/surfaceflinger/Scheduler/VsyncConfiguration.cpp11
-rw-r--r--services/surfaceflinger/Scheduler/VsyncConfiguration.h2
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp44
-rw-r--r--services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp35
6 files changed, 128 insertions, 22 deletions
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index c9d3b31061..16266c6b00 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -124,7 +124,10 @@ void Scheduler::setPacesetterDisplay(PhysicalDisplayId pacesetterId) {
// Cancel the pending refresh rate change, if any, before updating the phase configuration.
mVsyncModulator->cancelRefreshRateChange();
- mVsyncConfiguration->reset();
+ {
+ std::scoped_lock lock{mVsyncConfigLock};
+ mVsyncConfiguration->reset();
+ }
updatePhaseConfiguration(pacesetterId, pacesetterSelectorPtr()->getActiveMode().fps);
}
@@ -211,7 +214,7 @@ void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId,
.vsyncId = vsyncId,
.expectedVsyncTime = expectedVsyncTime,
.sfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration,
- .hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration,
+ .hwcMinWorkDuration = getCurrentVsyncConfigs().hwcMinWorkDuration,
.debugPresentTimeDelay = debugPresentDelay};
ftl::NonNull<const Display*> pacesetterPtr = pacesetterPtrLocked();
@@ -516,12 +519,26 @@ void Scheduler::updatePhaseConfiguration(PhysicalDisplayId displayId, Fps refres
if (!isPacesetter) return;
mRefreshRateStats->setRefreshRate(refreshRate);
- mVsyncConfiguration->setRefreshRateFps(refreshRate);
- setVsyncConfig(mVsyncModulator->setVsyncConfigSet(mVsyncConfiguration->getCurrentConfigs()),
- refreshRate.getPeriod());
+ const auto currentConfigs = [=, this] {
+ std::scoped_lock lock{mVsyncConfigLock};
+ mVsyncConfiguration->setRefreshRateFps(refreshRate);
+ return mVsyncConfiguration->getCurrentConfigs();
+ }();
+ setVsyncConfig(mVsyncModulator->setVsyncConfigSet(currentConfigs), refreshRate.getPeriod());
}
#pragma clang diagnostic pop
+void Scheduler::reloadPhaseConfiguration(Fps refreshRate, Duration minSfDuration,
+ Duration maxSfDuration, Duration appDuration) {
+ const auto currentConfigs = [=, this] {
+ std::scoped_lock lock{mVsyncConfigLock};
+ mVsyncConfiguration = std::make_unique<impl::WorkDuration>(refreshRate, minSfDuration,
+ maxSfDuration, appDuration);
+ return mVsyncConfiguration->getCurrentConfigs();
+ }();
+ setVsyncConfig(mVsyncModulator->setVsyncConfigSet(currentConfigs), refreshRate.getPeriod());
+}
+
void Scheduler::setActiveDisplayPowerModeForRefreshRateStats(hal::PowerMode powerMode) {
mRefreshRateStats->setPowerMode(powerMode);
}
@@ -896,8 +913,11 @@ void Scheduler::dump(utils::Dumper& dumper) const {
mFrameRateOverrideMappings.dump(dumper);
dumper.eol();
- mVsyncConfiguration->dump(dumper.out());
- dumper.eol();
+ {
+ std::scoped_lock lock{mVsyncConfigLock};
+ mVsyncConfiguration->dump(dumper.out());
+ dumper.eol();
+ }
mRefreshRateStats->dump(dumper.out());
dumper.eol();
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 61469c1b46..694856e9ce 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -53,6 +53,7 @@
#include "RefreshRateSelector.h"
#include "SmallAreaDetectionAllowMappings.h"
#include "Utils/Dumper.h"
+#include "VsyncConfiguration.h"
#include "VsyncModulator.h"
#include <FrontEnd/LayerHierarchy.h>
@@ -95,7 +96,7 @@ public:
// TODO: b/241285191 - Remove this API by promoting pacesetter in onScreen{Acquired,Released}.
void setPacesetterDisplay(PhysicalDisplayId) REQUIRES(kMainThreadContext)
- EXCLUDES(mDisplayLock);
+ EXCLUDES(mDisplayLock, mVsyncConfigLock);
using RefreshRateSelectorPtr = std::shared_ptr<RefreshRateSelector>;
@@ -188,9 +189,19 @@ public:
}
}
- void updatePhaseConfiguration(PhysicalDisplayId, Fps);
+ void updatePhaseConfiguration(PhysicalDisplayId, Fps) EXCLUDES(mVsyncConfigLock);
+ void reloadPhaseConfiguration(Fps, Duration minSfDuration, Duration maxSfDuration,
+ Duration appDuration) EXCLUDES(mVsyncConfigLock);
- const VsyncConfiguration& getVsyncConfiguration() const { return *mVsyncConfiguration; }
+ VsyncConfigSet getCurrentVsyncConfigs() const EXCLUDES(mVsyncConfigLock) {
+ std::scoped_lock lock{mVsyncConfigLock};
+ return mVsyncConfiguration->getCurrentConfigs();
+ }
+
+ VsyncConfigSet getVsyncConfigsForRefreshRate(Fps refreshRate) const EXCLUDES(mVsyncConfigLock) {
+ std::scoped_lock lock{mVsyncConfigLock};
+ return mVsyncConfiguration->getConfigsForRefreshRate(refreshRate);
+ }
// Sets the render rate for the scheduler to run at.
void setRenderRate(PhysicalDisplayId, Fps, bool applyImmediately);
@@ -266,7 +277,7 @@ public:
bool isVsyncInPhase(TimePoint expectedVsyncTime, Fps frameRate) const;
- void dump(utils::Dumper&) const;
+ void dump(utils::Dumper&) const EXCLUDES(mVsyncConfigLock);
void dump(Cycle, std::string&) const;
void dumpVsync(std::string&) const EXCLUDES(mDisplayLock);
@@ -348,7 +359,7 @@ private:
// impl::MessageQueue overrides:
void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override
- REQUIRES(kMainThreadContext, mDisplayLock);
+ REQUIRES(kMainThreadContext, mDisplayLock) EXCLUDES(mVsyncConfigLock);
// Used to skip event dispatch before EventThread creation during boot.
// TODO: b/241285191 - Reorder Scheduler initialization to avoid this.
@@ -476,8 +487,9 @@ private:
const FeatureFlags mFeatures;
+ mutable std::mutex mVsyncConfigLock;
// Stores phase offsets configured per refresh rate.
- const std::unique_ptr<VsyncConfiguration> mVsyncConfiguration;
+ std::unique_ptr<VsyncConfiguration> mVsyncConfiguration GUARDED_BY(mVsyncConfigLock);
// Shifts the VSYNC phase during certain transactions and refresh rate changes.
const sp<VsyncModulator> mVsyncModulator;
diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
index 6ae10f3d31..8cbb17c06e 100644
--- a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
@@ -362,6 +362,17 @@ WorkDuration::WorkDuration(Fps currentRefreshRate)
validateSysprops();
}
+WorkDuration::WorkDuration(Fps currentRefreshRate, Duration minSfDuration, Duration maxSfDuration,
+ Duration appDuration)
+ : WorkDuration(currentRefreshRate,
+ /*sfDuration*/ minSfDuration.ns(),
+ /*appDuration*/ appDuration.ns(),
+ /*sfEarlyDuration*/ maxSfDuration.ns(),
+ /*appEarlyDuration*/ appDuration.ns(),
+ /*sfEarlyGpuDuration*/ maxSfDuration.ns(),
+ /*appEarlyGpuDuration*/ appDuration.ns(),
+ /*hwcMinWorkDuration*/ 0) {}
+
WorkDuration::WorkDuration(Fps currentRefreshRate, nsecs_t sfDuration, nsecs_t appDuration,
nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
nsecs_t sfEarlyGpuDuration, nsecs_t appEarlyGpuDuration,
diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.h b/services/surfaceflinger/Scheduler/VsyncConfiguration.h
index b6cb373b7e..3d8ae3e5d4 100644
--- a/services/surfaceflinger/Scheduler/VsyncConfiguration.h
+++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.h
@@ -144,6 +144,8 @@ private:
class WorkDuration : public VsyncConfiguration {
public:
explicit WorkDuration(Fps currentRefreshRate);
+ WorkDuration(Fps currentRefreshRate, Duration minSfDuration, Duration maxSfDuration,
+ Duration appDuration);
protected:
// Used for unit tests
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 6b40c98d0a..9a0b87deca 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1226,8 +1226,8 @@ void SurfaceFlinger::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo*& info
outMode.peakRefreshRate = peakFps.getValue();
outMode.vsyncRate = mode->getVsyncRate().getValue();
- const auto vsyncConfigSet = mScheduler->getVsyncConfiguration().getConfigsForRefreshRate(
- Fps::fromValue(outMode.peakRefreshRate));
+ const auto vsyncConfigSet =
+ mScheduler->getVsyncConfigsForRefreshRate(Fps::fromValue(outMode.peakRefreshRate));
outMode.appVsyncOffset = vsyncConfigSet.late.appOffset;
outMode.sfVsyncOffset = vsyncConfigSet.late.sfOffset;
outMode.group = mode->getGroup();
@@ -3326,8 +3326,7 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId,
const auto schedule = mScheduler->getVsyncSchedule();
const TimePoint vsyncDeadline = schedule->vsyncDeadlineAfter(presentTime);
const Fps renderRate = pacesetterDisplay->refreshRateSelector().getActiveMode().fps;
- const nsecs_t vsyncPhase =
- mScheduler->getVsyncConfiguration().getCurrentConfigs().late.sfOffset;
+ const nsecs_t vsyncPhase = mScheduler->getCurrentVsyncConfigs().late.sfOffset;
const CompositorTiming compositorTiming(vsyncDeadline.ns(), renderRate.getPeriodNsecs(),
vsyncPhase, presentLatency.ns());
@@ -4657,7 +4656,7 @@ void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) {
/*applyImmediately*/ true);
}
- const auto configs = mScheduler->getVsyncConfiguration().getCurrentConfigs();
+ const auto configs = mScheduler->getCurrentVsyncConfigs();
mScheduler->createEventThread(scheduler::Cycle::Render, mFrameTimeline->getTokenManager(),
/* workDuration */ configs.late.appWorkDuration,
@@ -6647,9 +6646,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) {
code == IBinder::SYSPROPS_TRANSACTION) {
return OK;
}
- // Numbers from 1000 to 1045 are currently used for backdoors. The code
+ // Numbers from 1000 to 1047 are currently used for backdoors. The code
// in onTransact verifies that the user is root, and has access to use SF.
- if (code >= 1000 && code <= 1046) {
+ if (code >= 1000 && code <= 1047) {
ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
return OK;
}
@@ -7192,6 +7191,34 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
mScheduler->setDebugPresentDelay(TimePoint::fromNs(ms2ns(jankDelayMs)));
return NO_ERROR;
}
+ // Update WorkDuration
+ // parameters:
+ // - (required) i64 minSfNs, used as the late.sf WorkDuration.
+ // - (required) i64 maxSfNs, used as the early.sf and earlyGl.sf WorkDuration.
+ // - (required) i64 appDurationNs, used as the late.app, early.app and earlyGl.app
+ // WorkDuration.
+ // Usage:
+ // adb shell service call SurfaceFlinger 1047 i64 12333333 i64 16666666 i64 16666666
+ case 1047: {
+ if (!property_get_bool("debug.sf.use_phase_offsets_as_durations", false)) {
+ ALOGE("Not supported when work duration is not enabled");
+ return INVALID_OPERATION;
+ }
+ int64_t minSfNs = 0;
+ int64_t maxSfNs = 0;
+ int64_t appDurationNs = 0;
+ if (data.readInt64(&minSfNs) != NO_ERROR || data.readInt64(&maxSfNs) != NO_ERROR ||
+ data.readInt64(&appDurationNs) != NO_ERROR) {
+ return BAD_VALUE;
+ }
+ mScheduler->reloadPhaseConfiguration(mDisplayModeController
+ .getActiveMode(mActiveDisplayId)
+ .fps,
+ Duration::fromNs(minSfNs),
+ Duration::fromNs(maxSfNs),
+ Duration::fromNs(appDurationNs));
+ return NO_ERROR;
+ }
}
}
return err;
@@ -8376,8 +8403,7 @@ uint32_t SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t ui
}
int SurfaceFlinger::getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const {
- const auto vsyncConfig =
- mScheduler->getVsyncConfiguration().getConfigsForRefreshRate(refreshRate).late;
+ const auto vsyncConfig = mScheduler->getVsyncConfigsForRefreshRate(refreshRate).late;
const auto presentLatency = vsyncConfig.appWorkDuration + vsyncConfig.sfWorkDuration;
return calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
}
diff --git a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
index 21ee071f1b..3589553be0 100644
--- a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
@@ -22,6 +22,8 @@
#include <chrono>
#include <thread>
+#include <scheduler/Time.h>
+
#include "Scheduler/VsyncConfiguration.h"
using namespace testing;
@@ -39,6 +41,10 @@ public:
: impl::WorkDuration(currentFps, sfDuration, appDuration, sfEarlyDuration,
appEarlyDuration, sfEarlyGlDuration, appEarlyGlDuration,
hwcMinWorkDuration) {}
+
+ TestableWorkDuration(Fps currentFps, Duration minSfDuration, Duration maxSfDuration,
+ Duration appDuration)
+ : impl::WorkDuration(currentFps, minSfDuration, maxSfDuration, appDuration) {}
};
class WorkDurationTest : public testing::Test {
@@ -168,6 +174,35 @@ TEST_F(WorkDurationTest, minHwcWorkDuration) {
EXPECT_EQ(mWorkDuration.getCurrentConfigs().hwcMinWorkDuration, 1234ns);
}
+TEST_F(WorkDurationTest, workDurationIsARange) {
+ const Duration minSfDuration = Duration::fromNs(10'500'000);
+ const Duration maxSfDuration = Duration::fromNs(20'500'000);
+ const Duration appDuration = Duration::fromNs(16'000'000);
+ const TestableWorkDuration workDuration{60_Hz, minSfDuration, maxSfDuration, appDuration};
+
+ auto currentOffsets = workDuration.getCurrentConfigs();
+ auto offsets = workDuration.getConfigsForRefreshRate(60_Hz);
+
+ EXPECT_EQ(currentOffsets, offsets);
+ EXPECT_EQ(offsets.late.sfOffset, 6'166'667);
+ EXPECT_EQ(offsets.late.appOffset, 6'833'334);
+
+ EXPECT_EQ(offsets.late.sfWorkDuration, 10'500'000ns);
+ EXPECT_EQ(offsets.late.appWorkDuration, 16'000'000ns);
+
+ EXPECT_EQ(offsets.early.sfOffset, -3'833'333);
+ EXPECT_EQ(offsets.early.appOffset, 13'500'001);
+
+ EXPECT_EQ(offsets.early.sfWorkDuration, 20'500'000ns);
+ EXPECT_EQ(offsets.early.appWorkDuration, 16'000'000ns);
+
+ EXPECT_EQ(offsets.earlyGpu.sfOffset, -3'833'333);
+ EXPECT_EQ(offsets.earlyGpu.appOffset, 13'500'001);
+
+ EXPECT_EQ(offsets.earlyGpu.sfWorkDuration, 20'500'000ns);
+ EXPECT_EQ(offsets.earlyGpu.appWorkDuration, 16'000'000ns);
+}
+
class TestablePhaseOffsets : public impl::PhaseOffsets {
public:
TestablePhaseOffsets(nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs,