SurfaceFlinger: expose duration as part of phase offsets
expose app/sf duration together with the offset configs. These
will be used in the next CLs to calculate when to wake up the
corresponding EventThread.
Test: examine offsets and duration via dumpsys SurfaceFlinger
Bug: 162888874
Change-Id: Ifc1848358823570a34760f29ea975c286fbd8837
diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
index 5373742..aac2569 100644
--- a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp
@@ -51,145 +51,13 @@
} // namespace
-namespace android::scheduler {
+namespace android::scheduler::impl {
-PhaseConfiguration::~PhaseConfiguration() = default;
+VsyncConfiguration::VsyncConfiguration(float currentFps) : mRefreshRateFps(currentFps) {}
-namespace impl {
-
-PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs)
- : PhaseOffsets(getRefreshRatesFromConfigs(refreshRateConfigs),
- refreshRateConfigs.getCurrentRefreshRate().getFps(),
- sysprop::vsync_event_phase_offset_ns(1000000),
- sysprop::vsync_sf_event_phase_offset_ns(1000000),
- getProperty("debug.sf.early_phase_offset_ns"),
- getProperty("debug.sf.early_gl_phase_offset_ns"),
- getProperty("debug.sf.early_app_phase_offset_ns"),
- getProperty("debug.sf.early_gl_app_phase_offset_ns"),
- // Below defines the threshold when an offset is considered to be negative,
- // i.e. targeting for the N+2 vsync instead of N+1. This means that: For offset
- // < threshold, SF wake up (vsync_duration - offset) before HW vsync. For
- // offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW
- // vsync.
- getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
- .value_or(std::numeric_limits<nsecs_t>::max())) {}
-
-PhaseOffsets::PhaseOffsets(const std::vector<float>& refreshRates, float currentFps,
- nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs,
- std::optional<nsecs_t> earlySfOffsetNs,
- std::optional<nsecs_t> earlyGlSfOffsetNs,
- std::optional<nsecs_t> earlyAppOffsetNs,
- std::optional<nsecs_t> earlyGlAppOffsetNs, nsecs_t thresholdForNextVsync)
- : mVSyncPhaseOffsetNs(vsyncPhaseOffsetNs),
- mSfVSyncPhaseOffsetNs(sfVSyncPhaseOffsetNs),
- mEarlySfOffsetNs(earlySfOffsetNs),
- mEarlyGlSfOffsetNs(earlyGlSfOffsetNs),
- mEarlyAppOffsetNs(earlyAppOffsetNs),
- mEarlyGlAppOffsetNs(earlyGlAppOffsetNs),
- mThresholdForNextVsync(thresholdForNextVsync),
- mOffsets(initializeOffsets(refreshRates)),
- mRefreshRateFps(currentFps) {}
-
-void PhaseOffsets::dump(std::string& result) const {
- const auto [early, earlyGl, late] = getCurrentOffsets();
- using base::StringAppendF;
- StringAppendF(&result,
- " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n"
- " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n"
- " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n"
- "next VSYNC threshold: %9" PRId64 " ns\n",
- late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf,
- mThresholdForNextVsync);
-}
-
-std::unordered_map<float, PhaseOffsets::Offsets> PhaseOffsets::initializeOffsets(
- const std::vector<float>& refreshRates) const {
- std::unordered_map<float, Offsets> offsets;
-
- for (const auto& refreshRate : refreshRates) {
- offsets.emplace(refreshRate,
- getPhaseOffsets(refreshRate, static_cast<nsecs_t>(1e9f / refreshRate)));
- }
- return offsets;
-}
-
-PhaseOffsets::Offsets PhaseOffsets::getPhaseOffsets(float fps, nsecs_t vsyncPeriod) const {
- if (fps > 65.0f) {
- return getHighFpsOffsets(vsyncPeriod);
- } else {
- return getDefaultOffsets(vsyncPeriod);
- }
-}
-
-PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const {
- return {
- {
- mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
- ? mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
- : mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration,
-
- mEarlyAppOffsetNs.value_or(mVSyncPhaseOffsetNs),
- },
- {
- mEarlyGlSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
- ? mEarlyGlSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
- : mEarlyGlSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration,
-
- mEarlyGlAppOffsetNs.value_or(mVSyncPhaseOffsetNs),
- },
- {
- mSfVSyncPhaseOffsetNs < mThresholdForNextVsync
- ? mSfVSyncPhaseOffsetNs
- : mSfVSyncPhaseOffsetNs - vsyncDuration,
-
- mVSyncPhaseOffsetNs,
- },
- };
-}
-
-PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t vsyncDuration) const {
- const auto highFpsLateAppOffsetNs =
- getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000);
- const auto highFpsLateSfOffsetNs =
- getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000);
-
- const auto highFpsEarlySfOffsetNs = getProperty("debug.sf.high_fps_early_phase_offset_ns");
- const auto highFpsEarlyGlSfOffsetNs = getProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
- const auto highFpsEarlyAppOffsetNs = getProperty("debug.sf.high_fps_early_app_phase_offset_ns");
- const auto highFpsEarlyGlAppOffsetNs =
- getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
-
- return {
- {
- highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) < mThresholdForNextVsync
- ? highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs)
- : highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs) -
- vsyncDuration,
-
- highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs),
- },
- {
- highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) <
- mThresholdForNextVsync
- ? highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs)
- : highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs) -
- vsyncDuration,
-
- highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs),
- },
- {
- highFpsLateSfOffsetNs < mThresholdForNextVsync
- ? highFpsLateSfOffsetNs
- : highFpsLateSfOffsetNs - vsyncDuration,
-
- highFpsLateAppOffsetNs,
- },
- };
-}
-
-PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(float fps) const {
+PhaseOffsets::VsyncConfigSet VsyncConfiguration::getConfigsForRefreshRate(float fps) const {
const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(),
- [&fps](const std::pair<float, Offsets>& candidateFps) {
+ [&fps](const std::pair<float, VsyncConfigSet>& candidateFps) {
return fpsEqualsWithMargin(fps, candidateFps.first);
});
@@ -200,7 +68,194 @@
// Unknown refresh rate. This might happen if we get a hotplug event for an external display.
// In this case just construct the offset.
ALOGW("Can't find offset for %.2f fps", fps);
- return getPhaseOffsets(fps, static_cast<nsecs_t>(1e9f / fps));
+ return constructOffsets(static_cast<nsecs_t>(1e9f / fps));
+}
+
+void VsyncConfiguration::initializeOffsets(const std::vector<float>& refreshRates) {
+ for (const auto fps : refreshRates) {
+ mOffsets.emplace(fps, constructOffsets(static_cast<nsecs_t>(1e9f / fps)));
+ }
+}
+
+void VsyncConfiguration::dump(std::string& result) const {
+ const auto [early, earlyGpu, late] = getCurrentConfigs();
+ using base::StringAppendF;
+ StringAppendF(&result,
+ " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64
+ " ns\n"
+ " app duration: %9lld ns\t SF duration: %9lld ns\n"
+ " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64
+ " ns\n"
+ " early app duration: %9lld ns\t early SF duration: %9lld ns\n"
+ " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64
+ " ns\n"
+ " GL early app duration: %9lld ns\tGL early SF duration: %9lld ns\n",
+ late.appOffset, late.sfOffset,
+
+ late.appWorkDuration.count(), late.sfWorkDuration.count(),
+
+ early.appOffset, early.sfOffset,
+
+ early.appWorkDuration.count(), early.sfWorkDuration.count(),
+
+ earlyGpu.appOffset, earlyGpu.sfOffset,
+
+ earlyGpu.appWorkDuration.count(), earlyGpu.sfWorkDuration.count());
+}
+
+PhaseOffsets::PhaseOffsets(const scheduler::RefreshRateConfigs& refreshRateConfigs)
+ : PhaseOffsets(getRefreshRatesFromConfigs(refreshRateConfigs),
+ refreshRateConfigs.getCurrentRefreshRate().getFps(),
+ sysprop::vsync_event_phase_offset_ns(1000000),
+ sysprop::vsync_sf_event_phase_offset_ns(1000000),
+ getProperty("debug.sf.early_phase_offset_ns"),
+ getProperty("debug.sf.early_gl_phase_offset_ns"),
+ getProperty("debug.sf.early_app_phase_offset_ns"),
+ getProperty("debug.sf.early_gl_app_phase_offset_ns"),
+ getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000),
+ getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000),
+ getProperty("debug.sf.high_fps_early_phase_offset_ns"),
+ getProperty("debug.sf.high_fps_early_gl_phase_offset_ns"),
+ getProperty("debug.sf.high_fps_early_app_phase_offset_ns"),
+ getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns"),
+ // Below defines the threshold when an offset is considered to be negative,
+ // i.e. targeting for the N+2 vsync instead of N+1. This means that: For offset
+ // < threshold, SF wake up (vsync_duration - offset) before HW vsync. For
+ // offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW
+ // vsync.
+ getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
+ .value_or(std::numeric_limits<nsecs_t>::max())) {}
+
+PhaseOffsets::PhaseOffsets(
+ const std::vector<float>& refreshRates, float currentFps, nsecs_t vsyncPhaseOffsetNs,
+ nsecs_t sfVSyncPhaseOffsetNs, std::optional<nsecs_t> earlySfOffsetNs,
+ std::optional<nsecs_t> earlyGpuSfOffsetNs, std::optional<nsecs_t> earlyAppOffsetNs,
+ std::optional<nsecs_t> earlyGpuAppOffsetNs, nsecs_t highFpsVsyncPhaseOffsetNs,
+ nsecs_t highFpsSfVSyncPhaseOffsetNs, std::optional<nsecs_t> highFpsEarlySfOffsetNs,
+ std::optional<nsecs_t> highFpsEarlyGpuSfOffsetNs,
+ std::optional<nsecs_t> highFpsEarlyAppOffsetNs,
+ std::optional<nsecs_t> highFpsEarlyGpuAppOffsetNs, nsecs_t thresholdForNextVsync)
+ : VsyncConfiguration(currentFps),
+ mVSyncPhaseOffsetNs(vsyncPhaseOffsetNs),
+ mSfVSyncPhaseOffsetNs(sfVSyncPhaseOffsetNs),
+ mEarlySfOffsetNs(earlySfOffsetNs),
+ mEarlyGpuSfOffsetNs(earlyGpuSfOffsetNs),
+ mEarlyAppOffsetNs(earlyAppOffsetNs),
+ mEarlyGpuAppOffsetNs(earlyGpuAppOffsetNs),
+ mHighFpsVSyncPhaseOffsetNs(highFpsVsyncPhaseOffsetNs),
+ mHighFpsSfVSyncPhaseOffsetNs(highFpsSfVSyncPhaseOffsetNs),
+ mHighFpsEarlySfOffsetNs(highFpsEarlySfOffsetNs),
+ mHighFpsEarlyGpuSfOffsetNs(highFpsEarlyGpuSfOffsetNs),
+ mHighFpsEarlyAppOffsetNs(highFpsEarlyAppOffsetNs),
+ mHighFpsEarlyGpuAppOffsetNs(highFpsEarlyGpuAppOffsetNs),
+ mThresholdForNextVsync(thresholdForNextVsync) {
+ initializeOffsets(refreshRates);
+}
+
+PhaseOffsets::VsyncConfigSet PhaseOffsets::constructOffsets(nsecs_t vsyncDuration) const {
+ if (vsyncDuration < std::chrono::nanoseconds(15ms).count()) {
+ return getHighFpsOffsets(vsyncDuration);
+ } else {
+ return getDefaultOffsets(vsyncDuration);
+ }
+}
+
+namespace {
+std::chrono::nanoseconds sfOffsetToDuration(nsecs_t sfOffset, nsecs_t vsyncDuration) {
+ return std::chrono::nanoseconds(vsyncDuration - sfOffset);
+}
+
+std::chrono::nanoseconds appOffsetToDuration(nsecs_t appOffset, nsecs_t sfOffset,
+ nsecs_t vsyncDuration) {
+ auto duration = vsyncDuration + (sfOffset - appOffset);
+ if (duration < vsyncDuration) {
+ duration += vsyncDuration;
+ }
+
+ return std::chrono::nanoseconds(duration);
+}
+} // namespace
+
+PhaseOffsets::VsyncConfigSet PhaseOffsets::getDefaultOffsets(nsecs_t vsyncDuration) const {
+ const auto earlySfOffset =
+ mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
+
+ ? mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
+ : mEarlySfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration;
+ const auto earlyAppOffset = mEarlyAppOffsetNs.value_or(mVSyncPhaseOffsetNs);
+ const auto earlyGpuSfOffset =
+ mEarlyGpuSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
+
+ ? mEarlyGpuSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs)
+ : mEarlyGpuSfOffsetNs.value_or(mSfVSyncPhaseOffsetNs) - vsyncDuration;
+ const auto earlyGpuAppOffset = mEarlyGpuAppOffsetNs.value_or(mVSyncPhaseOffsetNs);
+ const auto lateSfOffset = mSfVSyncPhaseOffsetNs < mThresholdForNextVsync
+ ? mSfVSyncPhaseOffsetNs
+ : mSfVSyncPhaseOffsetNs - vsyncDuration;
+ const auto lateAppOffset = mVSyncPhaseOffsetNs;
+
+ return {
+ .early = {.sfOffset = earlySfOffset,
+ .appOffset = earlyAppOffset,
+ .sfWorkDuration = sfOffsetToDuration(earlySfOffset, vsyncDuration),
+ .appWorkDuration =
+ appOffsetToDuration(earlyAppOffset, earlySfOffset, vsyncDuration)},
+ .earlyGpu = {.sfOffset = earlyGpuSfOffset,
+ .appOffset = earlyGpuAppOffset,
+ .sfWorkDuration = sfOffsetToDuration(earlyGpuSfOffset, vsyncDuration),
+ .appWorkDuration = appOffsetToDuration(earlyGpuAppOffset, earlyGpuSfOffset,
+ vsyncDuration)},
+ .late = {.sfOffset = lateSfOffset,
+ .appOffset = lateAppOffset,
+ .sfWorkDuration = sfOffsetToDuration(lateSfOffset, vsyncDuration),
+ .appWorkDuration =
+ appOffsetToDuration(lateAppOffset, lateSfOffset, vsyncDuration)},
+ };
+}
+
+PhaseOffsets::VsyncConfigSet PhaseOffsets::getHighFpsOffsets(nsecs_t vsyncDuration) const {
+ const auto earlySfOffset =
+ mHighFpsEarlySfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
+ ? mHighFpsEarlySfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs)
+ : mHighFpsEarlySfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs) - vsyncDuration;
+ const auto earlyAppOffset = mHighFpsEarlyAppOffsetNs.value_or(mHighFpsVSyncPhaseOffsetNs);
+ const auto earlyGpuSfOffset = mHighFpsEarlyGpuSfOffsetNs.value_or(
+ mHighFpsSfVSyncPhaseOffsetNs) < mThresholdForNextVsync
+
+ ? mHighFpsEarlyGpuSfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs)
+ : mHighFpsEarlyGpuSfOffsetNs.value_or(mHighFpsSfVSyncPhaseOffsetNs) - vsyncDuration;
+ const auto earlyGpuAppOffset = mHighFpsEarlyGpuAppOffsetNs.value_or(mHighFpsVSyncPhaseOffsetNs);
+ const auto lateSfOffset = mHighFpsSfVSyncPhaseOffsetNs < mThresholdForNextVsync
+ ? mHighFpsSfVSyncPhaseOffsetNs
+ : mHighFpsSfVSyncPhaseOffsetNs - vsyncDuration;
+ const auto lateAppOffset = mHighFpsVSyncPhaseOffsetNs;
+
+ return {
+ .early =
+ {
+ .sfOffset = earlySfOffset,
+ .appOffset = earlyAppOffset,
+ .sfWorkDuration = sfOffsetToDuration(earlySfOffset, vsyncDuration),
+ .appWorkDuration = appOffsetToDuration(earlyAppOffset, earlySfOffset,
+ vsyncDuration),
+ },
+ .earlyGpu =
+ {
+ .sfOffset = earlyGpuSfOffset,
+ .appOffset = earlyGpuAppOffset,
+ .sfWorkDuration = sfOffsetToDuration(earlyGpuSfOffset, vsyncDuration),
+ .appWorkDuration = appOffsetToDuration(earlyGpuAppOffset,
+ earlyGpuSfOffset, vsyncDuration),
+ },
+ .late =
+ {
+ .sfOffset = lateSfOffset,
+ .appOffset = lateAppOffset,
+ .sfWorkDuration = sfOffsetToDuration(lateSfOffset, vsyncDuration),
+ .appWorkDuration =
+ appOffsetToDuration(lateAppOffset, lateSfOffset, vsyncDuration),
+ },
+ };
}
static void validateSysprops() {
@@ -236,123 +291,105 @@
validateProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
}
-static nsecs_t sfDurationToOffset(nsecs_t sfDuration, nsecs_t vsyncDuration) {
- return sfDuration == -1 ? 1'000'000 : vsyncDuration - sfDuration % vsyncDuration;
+namespace {
+nsecs_t sfDurationToOffset(std::chrono::nanoseconds sfDuration, nsecs_t vsyncDuration) {
+ return vsyncDuration - sfDuration.count() % vsyncDuration;
}
-static nsecs_t appDurationToOffset(nsecs_t appDuration, nsecs_t sfDuration, nsecs_t vsyncDuration) {
- return sfDuration == -1 ? 1'000'000
- : vsyncDuration - (appDuration + sfDuration) % vsyncDuration;
+nsecs_t appDurationToOffset(std::chrono::nanoseconds appDuration,
+ std::chrono::nanoseconds sfDuration, nsecs_t vsyncDuration) {
+ return vsyncDuration - (appDuration + sfDuration).count() % vsyncDuration;
}
+} // namespace
-PhaseDurations::Offsets PhaseDurations::constructOffsets(nsecs_t vsyncDuration) const {
- return Offsets{
- {
- mSfEarlyDuration < vsyncDuration
- ? sfDurationToOffset(mSfEarlyDuration, vsyncDuration)
- : sfDurationToOffset(mSfEarlyDuration, vsyncDuration) - vsyncDuration,
+WorkDuration::VsyncConfigSet WorkDuration::constructOffsets(nsecs_t vsyncDuration) const {
+ const auto sfDurationFixup = [vsyncDuration](nsecs_t duration) {
+ return duration == -1 ? std::chrono::nanoseconds(vsyncDuration) - 1ms
+ : std::chrono::nanoseconds(duration);
+ };
- appDurationToOffset(mAppEarlyDuration, mSfEarlyDuration, vsyncDuration),
- },
- {
- mSfEarlyGlDuration < vsyncDuration
- ? sfDurationToOffset(mSfEarlyGlDuration, vsyncDuration)
- : sfDurationToOffset(mSfEarlyGlDuration, vsyncDuration) - vsyncDuration,
+ const auto appDurationFixup = [vsyncDuration](nsecs_t duration) {
+ return duration == -1 ? std::chrono::nanoseconds(vsyncDuration)
+ : std::chrono::nanoseconds(duration);
+ };
- appDurationToOffset(mAppEarlyGlDuration, mSfEarlyGlDuration, vsyncDuration),
- },
- {
- mSfDuration < vsyncDuration
- ? sfDurationToOffset(mSfDuration, vsyncDuration)
- : sfDurationToOffset(mSfDuration, vsyncDuration) - vsyncDuration,
+ const auto sfEarlyDuration = sfDurationFixup(mSfEarlyDuration);
+ const auto appEarlyDuration = appDurationFixup(mAppEarlyDuration);
+ const auto sfEarlyGpuDuration = sfDurationFixup(mSfEarlyGpuDuration);
+ const auto appEarlyGpuDuration = appDurationFixup(mAppEarlyGpuDuration);
+ const auto sfDuration = sfDurationFixup(mSfDuration);
+ const auto appDuration = appDurationFixup(mAppDuration);
- appDurationToOffset(mAppDuration, mSfDuration, vsyncDuration),
- },
+ return {
+ .early =
+ {
+
+ .sfOffset = sfEarlyDuration.count() < vsyncDuration
+ ? sfDurationToOffset(sfEarlyDuration, vsyncDuration)
+ : sfDurationToOffset(sfEarlyDuration, vsyncDuration) -
+ vsyncDuration,
+
+ .appOffset = appDurationToOffset(appEarlyDuration, sfEarlyDuration,
+ vsyncDuration),
+
+ .sfWorkDuration = sfEarlyDuration,
+ .appWorkDuration = appEarlyDuration,
+ },
+ .earlyGpu =
+ {
+
+ .sfOffset = sfEarlyGpuDuration.count() < vsyncDuration
+
+ ? sfDurationToOffset(sfEarlyGpuDuration, vsyncDuration)
+ : sfDurationToOffset(sfEarlyGpuDuration, vsyncDuration) -
+ vsyncDuration,
+
+ .appOffset = appDurationToOffset(appEarlyGpuDuration,
+ sfEarlyGpuDuration, vsyncDuration),
+ .sfWorkDuration = sfEarlyGpuDuration,
+ .appWorkDuration = appEarlyGpuDuration,
+ },
+ .late =
+ {
+
+ .sfOffset = sfDuration.count() < vsyncDuration
+
+ ? sfDurationToOffset(sfDuration, vsyncDuration)
+ : sfDurationToOffset(sfDuration, vsyncDuration) - vsyncDuration,
+
+ .appOffset =
+ appDurationToOffset(appDuration, sfDuration, vsyncDuration),
+
+ .sfWorkDuration = sfDuration,
+ .appWorkDuration = appDuration,
+ },
};
}
-std::unordered_map<float, PhaseDurations::Offsets> PhaseDurations::initializeOffsets(
- const std::vector<float>& refreshRates) const {
- std::unordered_map<float, Offsets> offsets;
-
- for (const auto fps : refreshRates) {
- offsets.emplace(fps, constructOffsets(static_cast<nsecs_t>(1e9f / fps)));
- }
- return offsets;
-}
-
-PhaseDurations::PhaseDurations(const scheduler::RefreshRateConfigs& refreshRateConfigs)
- : PhaseDurations(getRefreshRatesFromConfigs(refreshRateConfigs),
- refreshRateConfigs.getCurrentRefreshRate().getFps(),
- getProperty("debug.sf.late.sf.duration").value_or(-1),
- getProperty("debug.sf.late.app.duration").value_or(-1),
- getProperty("debug.sf.early.sf.duration").value_or(mSfDuration),
- getProperty("debug.sf.early.app.duration").value_or(mAppDuration),
- getProperty("debug.sf.earlyGl.sf.duration").value_or(mSfDuration),
- getProperty("debug.sf.earlyGl.app.duration").value_or(mAppDuration)) {
+WorkDuration::WorkDuration(const scheduler::RefreshRateConfigs& refreshRateConfigs)
+ : WorkDuration(getRefreshRatesFromConfigs(refreshRateConfigs),
+ refreshRateConfigs.getCurrentRefreshRate().getFps(),
+ getProperty("debug.sf.late.sf.duration").value_or(-1),
+ getProperty("debug.sf.late.app.duration").value_or(-1),
+ getProperty("debug.sf.early.sf.duration").value_or(mSfDuration),
+ getProperty("debug.sf.early.app.duration").value_or(mAppDuration),
+ getProperty("debug.sf.earlyGl.sf.duration").value_or(mSfDuration),
+ getProperty("debug.sf.earlyGl.app.duration").value_or(mAppDuration)) {
validateSysprops();
}
-PhaseDurations::PhaseDurations(const std::vector<float>& refreshRates, float currentFps,
- nsecs_t sfDuration, nsecs_t appDuration, nsecs_t sfEarlyDuration,
- nsecs_t appEarlyDuration, nsecs_t sfEarlyGlDuration,
- nsecs_t appEarlyGlDuration)
- : mSfDuration(sfDuration),
+WorkDuration::WorkDuration(const std::vector<float>& refreshRates, float currentFps,
+ nsecs_t sfDuration, nsecs_t appDuration, nsecs_t sfEarlyDuration,
+ nsecs_t appEarlyDuration, nsecs_t sfEarlyGpuDuration,
+ nsecs_t appEarlyGpuDuration)
+ : VsyncConfiguration(currentFps),
+ mSfDuration(sfDuration),
mAppDuration(appDuration),
mSfEarlyDuration(sfEarlyDuration),
mAppEarlyDuration(appEarlyDuration),
- mSfEarlyGlDuration(sfEarlyGlDuration),
- mAppEarlyGlDuration(appEarlyGlDuration),
- mOffsets(initializeOffsets(refreshRates)),
- mRefreshRateFps(currentFps) {}
-
-PhaseOffsets::Offsets PhaseDurations::getOffsetsForRefreshRate(float fps) const {
- const auto iter = std::find_if(mOffsets.begin(), mOffsets.end(), [=](const auto& candidateFps) {
- return fpsEqualsWithMargin(fps, candidateFps.first);
- });
-
- if (iter != mOffsets.end()) {
- return iter->second;
- }
-
- // Unknown refresh rate. This might happen if we get a hotplug event for an external display.
- // In this case just construct the offset.
- ALOGW("Can't find offset for %.2f fps", fps);
- return constructOffsets(static_cast<nsecs_t>(1e9f / fps));
+ mSfEarlyGpuDuration(sfEarlyGpuDuration),
+ mAppEarlyGpuDuration(appEarlyGpuDuration) {
+ initializeOffsets(refreshRates);
}
-void PhaseDurations::dump(std::string& result) const {
- const auto [early, earlyGl, late] = getCurrentOffsets();
- using base::StringAppendF;
- StringAppendF(&result,
- " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64
- " ns\n"
- " app duration: %9" PRId64 " ns\t SF duration: %9" PRId64
- " ns\n"
- " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64
- " ns\n"
- " early app duration: %9" PRId64 " ns\t early SF duration: %9" PRId64
- " ns\n"
- " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64
- " ns\n"
- " GL early app duration: %9" PRId64 " ns\tGL early SF duration: %9" PRId64
- " ns\n",
- late.app,
-
- late.sf,
-
- mAppDuration, mSfDuration,
-
- early.app, early.sf,
-
- mAppEarlyDuration, mSfEarlyDuration,
-
- earlyGl.app,
-
- earlyGl.sf,
-
- mAppEarlyGlDuration, mSfEarlyGlDuration);
-}
-
-} // namespace impl
-} // namespace android::scheduler
+} // namespace android::scheduler::impl
diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.h b/services/surfaceflinger/Scheduler/VsyncConfiguration.h
index 0ae9fef..c27a25d 100644
--- a/services/surfaceflinger/Scheduler/VsyncConfiguration.h
+++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.h
@@ -24,19 +24,18 @@
namespace android::scheduler {
/*
- * This class encapsulates offsets for different refresh rates. Depending
+ * This class encapsulates vsync configurations for different refresh rates. Depending
* on what refresh rate we are using, and wheter we are composing in GL,
* different offsets will help us with latency. This class keeps track of
* which mode the device is on, and returns approprate offsets when needed.
*/
-class PhaseConfiguration {
+class VsyncConfiguration {
public:
- using Offsets = VsyncModulator::OffsetsConfig;
+ using VsyncConfigSet = VsyncModulator::VsyncConfigSet;
- virtual ~PhaseConfiguration();
-
- virtual Offsets getCurrentOffsets() const = 0;
- virtual Offsets getOffsetsForRefreshRate(float fps) const = 0;
+ virtual ~VsyncConfiguration() = default;
+ virtual VsyncConfigSet getCurrentConfigs() const = 0;
+ virtual VsyncConfigSet getConfigsForRefreshRate(float fps) const = 0;
virtual void setRefreshRateFps(float fps) = 0;
@@ -46,18 +45,21 @@
namespace impl {
/*
- * This is the old implementation of phase offsets and considered as deprecated.
- * PhaseDurations is the new implementation.
+ * This is a common implementation for both phase offsets and durations.
+ * PhaseOffsets and WorkDuration derive from this class and implement the
+ * constructOffsets method
*/
-class PhaseOffsets : public scheduler::PhaseConfiguration {
+class VsyncConfiguration : public scheduler::VsyncConfiguration {
public:
- PhaseOffsets(const scheduler::RefreshRateConfigs&);
+ explicit VsyncConfiguration(float currentFps);
// Returns early, early GL, and late offsets for Apps and SF for a given refresh rate.
- Offsets getOffsetsForRefreshRate(float fps) const override;
+ VsyncConfigSet getConfigsForRefreshRate(float fps) const override;
// Returns early, early GL, and late offsets for Apps and SF.
- Offsets getCurrentOffsets() const override { return getOffsetsForRefreshRate(mRefreshRateFps); }
+ VsyncConfigSet getCurrentConfigs() const override {
+ return getConfigsForRefreshRate(mRefreshRateFps);
+ }
// This function should be called when the device is switching between different
// refresh rates, to properly update the offsets.
@@ -67,61 +69,73 @@
void dump(std::string& result) const override;
protected:
+ void initializeOffsets(const std::vector<float>& refreshRates);
+ virtual VsyncConfiguration::VsyncConfigSet constructOffsets(nsecs_t vsyncDuration) const = 0;
+
+ std::unordered_map<float, VsyncConfigSet> mOffsets;
+ std::atomic<float> mRefreshRateFps;
+};
+
+/*
+ * This is the old implementation of phase offsets and considered as deprecated.
+ * WorkDuration is the new implementation.
+ */
+class PhaseOffsets : public VsyncConfiguration {
+public:
+ explicit PhaseOffsets(const scheduler::RefreshRateConfigs&);
+
+protected:
// Used for unit tests
PhaseOffsets(const std::vector<float>& refreshRates, float currentFps,
nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs,
- std::optional<nsecs_t> earlySfOffsetNs, std::optional<nsecs_t> earlyGlSfOffsetNs,
- std::optional<nsecs_t> earlyAppOffsetNs, std::optional<nsecs_t> earlyGlAppOffsetNs,
- nsecs_t thresholdForNextVsync);
- std::unordered_map<float, Offsets> initializeOffsets(
- const std::vector<float>& refreshRates) const;
- Offsets getDefaultOffsets(nsecs_t vsyncPeriod) const;
- Offsets getHighFpsOffsets(nsecs_t vsyncPeriod) const;
- Offsets getPhaseOffsets(float fps, nsecs_t vsyncPeriod) const;
+ std::optional<nsecs_t> earlySfOffsetNs, std::optional<nsecs_t> earlyGpuSfOffsetNs,
+ std::optional<nsecs_t> earlyAppOffsetNs,
+ std::optional<nsecs_t> earlyGpuAppOffsetNs, nsecs_t highFpsVsyncPhaseOffsetNs,
+ nsecs_t highFpsSfVSyncPhaseOffsetNs, std::optional<nsecs_t> highFpsEarlySfOffsetNs,
+ std::optional<nsecs_t> highFpsEarlyGpuSfOffsetNs,
+ std::optional<nsecs_t> highFpsEarlyAppOffsetNs,
+ std::optional<nsecs_t> highFpsEarlyGpuAppOffsetNs, nsecs_t thresholdForNextVsync);
+
+private:
+ VsyncConfiguration::VsyncConfigSet constructOffsets(nsecs_t vsyncDuration) const override;
+
+ VsyncConfigSet getDefaultOffsets(nsecs_t vsyncPeriod) const;
+ VsyncConfigSet getHighFpsOffsets(nsecs_t vsyncPeriod) const;
const nsecs_t mVSyncPhaseOffsetNs;
const nsecs_t mSfVSyncPhaseOffsetNs;
const std::optional<nsecs_t> mEarlySfOffsetNs;
- const std::optional<nsecs_t> mEarlyGlSfOffsetNs;
+ const std::optional<nsecs_t> mEarlyGpuSfOffsetNs;
const std::optional<nsecs_t> mEarlyAppOffsetNs;
- const std::optional<nsecs_t> mEarlyGlAppOffsetNs;
- const nsecs_t mThresholdForNextVsync;
- const std::unordered_map<float, Offsets> mOffsets;
+ const std::optional<nsecs_t> mEarlyGpuAppOffsetNs;
- std::atomic<float> mRefreshRateFps;
+ const nsecs_t mHighFpsVSyncPhaseOffsetNs;
+ const nsecs_t mHighFpsSfVSyncPhaseOffsetNs;
+ const std::optional<nsecs_t> mHighFpsEarlySfOffsetNs;
+ const std::optional<nsecs_t> mHighFpsEarlyGpuSfOffsetNs;
+ const std::optional<nsecs_t> mHighFpsEarlyAppOffsetNs;
+ const std::optional<nsecs_t> mHighFpsEarlyGpuAppOffsetNs;
+
+ const nsecs_t mThresholdForNextVsync;
};
/*
* Class that encapsulates the phase offsets for SurfaceFlinger and App.
- * The offsets are calculated from durations for each one of the (late, early, earlyGL)
+ * The offsets are calculated from durations for each one of the (late, early, earlyGpu)
* offset types.
*/
-class PhaseDurations : public scheduler::PhaseConfiguration {
+class WorkDuration : public VsyncConfiguration {
public:
- PhaseDurations(const scheduler::RefreshRateConfigs&);
-
- // Returns early, early GL, and late offsets for Apps and SF for a given refresh rate.
- Offsets getOffsetsForRefreshRate(float fps) const override;
-
- // Returns early, early GL, and late offsets for Apps and SF.
- Offsets getCurrentOffsets() const override { return getOffsetsForRefreshRate(mRefreshRateFps); }
-
- // This function should be called when the device is switching between different
- // refresh rates, to properly update the offsets.
- void setRefreshRateFps(float fps) override { mRefreshRateFps = fps; }
-
- // Returns current offsets in human friendly format.
- void dump(std::string& result) const override;
+ explicit WorkDuration(const scheduler::RefreshRateConfigs&);
protected:
// Used for unit tests
- PhaseDurations(const std::vector<float>& refreshRates, float currentFps, nsecs_t sfDuration,
- nsecs_t appDuration, nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
- nsecs_t sfEarlyGlDuration, nsecs_t appEarlyGlDuration);
+ WorkDuration(const std::vector<float>& refreshRates, float currentFps, nsecs_t sfDuration,
+ nsecs_t appDuration, nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
+ nsecs_t sfEarlyGpuDuration, nsecs_t appEarlyGpuDuration);
private:
- std::unordered_map<float, Offsets> initializeOffsets(const std::vector<float>&) const;
- PhaseDurations::Offsets constructOffsets(nsecs_t vsyncDuration) const;
+ VsyncConfiguration::VsyncConfigSet constructOffsets(nsecs_t vsyncDuration) const override;
const nsecs_t mSfDuration;
const nsecs_t mAppDuration;
@@ -129,12 +143,8 @@
const nsecs_t mSfEarlyDuration;
const nsecs_t mAppEarlyDuration;
- const nsecs_t mSfEarlyGlDuration;
- const nsecs_t mAppEarlyGlDuration;
-
- const std::unordered_map<float, Offsets> mOffsets;
-
- std::atomic<float> mRefreshRateFps;
+ const nsecs_t mSfEarlyGpuDuration;
+ const nsecs_t mAppEarlyGpuDuration;
};
} // namespace impl
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.cpp b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
index 7a1b7e4..1f821be 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
@@ -35,18 +35,19 @@
const std::chrono::nanoseconds VsyncModulator::MIN_EARLY_TRANSACTION_TIME = 1ms;
-VsyncModulator::VsyncModulator(const OffsetsConfig& config, Now now)
- : mOffsetsConfig(config),
+VsyncModulator::VsyncModulator(const VsyncConfigSet& config, Now now)
+ : mVsyncConfigSet(config),
mNow(now),
mTraceDetailedInfo(base::GetBoolProperty("debug.sf.vsync_trace_detailed_info", false)) {}
-VsyncModulator::Offsets VsyncModulator::setPhaseOffsets(const OffsetsConfig& config) {
+VsyncModulator::VsyncConfig VsyncModulator::setVsyncConfigSet(const VsyncConfigSet& config) {
std::lock_guard<std::mutex> lock(mMutex);
- mOffsetsConfig = config;
- return updateOffsetsLocked();
+ mVsyncConfigSet = config;
+ return updateVsyncConfigLocked();
}
-VsyncModulator::OffsetsOpt VsyncModulator::setTransactionSchedule(TransactionSchedule schedule) {
+VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule(
+ TransactionSchedule schedule) {
switch (schedule) {
case Schedule::EarlyStart:
ALOGW_IF(mExplicitEarlyWakeup, "%s: Duplicate EarlyStart", __FUNCTION__);
@@ -76,29 +77,29 @@
return std::nullopt;
}
mTransactionSchedule = schedule;
- return updateOffsets();
+ return updateVsyncConfig();
}
-VsyncModulator::OffsetsOpt VsyncModulator::onTransactionCommit() {
+VsyncModulator::VsyncConfigOpt VsyncModulator::onTransactionCommit() {
mLastTransactionCommitTime = mNow();
if (mTransactionSchedule == Schedule::Late) return std::nullopt;
mTransactionSchedule = Schedule::Late;
- return updateOffsets();
+ return updateVsyncConfig();
}
-VsyncModulator::OffsetsOpt VsyncModulator::onRefreshRateChangeInitiated() {
+VsyncModulator::VsyncConfigOpt VsyncModulator::onRefreshRateChangeInitiated() {
if (mRefreshRateChangePending) return std::nullopt;
mRefreshRateChangePending = true;
- return updateOffsets();
+ return updateVsyncConfig();
}
-VsyncModulator::OffsetsOpt VsyncModulator::onRefreshRateChangeCompleted() {
+VsyncModulator::VsyncConfigOpt VsyncModulator::onRefreshRateChangeCompleted() {
if (!mRefreshRateChangePending) return std::nullopt;
mRefreshRateChangePending = false;
- return updateOffsets();
+ return updateVsyncConfig();
}
-VsyncModulator::OffsetsOpt VsyncModulator::onDisplayRefresh(bool usedGpuComposition) {
+VsyncModulator::VsyncConfigOpt VsyncModulator::onDisplayRefresh(bool usedGpuComposition) {
bool updateOffsetsNeeded = false;
if (mEarlyTransactionStartTime.load() + MIN_EARLY_TRANSACTION_TIME <=
@@ -117,40 +118,40 @@
}
if (!updateOffsetsNeeded) return std::nullopt;
- return updateOffsets();
+ return updateVsyncConfig();
}
-VsyncModulator::Offsets VsyncModulator::getOffsets() const {
+VsyncModulator::VsyncConfig VsyncModulator::getVsyncConfig() const {
std::lock_guard<std::mutex> lock(mMutex);
- return mOffsets;
+ return mVsyncConfig;
}
-const VsyncModulator::Offsets& VsyncModulator::getNextOffsets() const {
+const VsyncModulator::VsyncConfig& VsyncModulator::getNextVsyncConfig() const {
// Early offsets are used if we're in the middle of a refresh rate
// change, or if we recently begin a transaction.
if (mExplicitEarlyWakeup || mTransactionSchedule == Schedule::EarlyEnd ||
mEarlyTransactionFrames > 0 || mRefreshRateChangePending) {
- return mOffsetsConfig.early;
+ return mVsyncConfigSet.early;
} else if (mEarlyGpuFrames > 0) {
- return mOffsetsConfig.earlyGpu;
+ return mVsyncConfigSet.earlyGpu;
} else {
- return mOffsetsConfig.late;
+ return mVsyncConfigSet.late;
}
}
-VsyncModulator::Offsets VsyncModulator::updateOffsets() {
+VsyncModulator::VsyncConfig VsyncModulator::updateVsyncConfig() {
std::lock_guard<std::mutex> lock(mMutex);
- return updateOffsetsLocked();
+ return updateVsyncConfigLocked();
}
-VsyncModulator::Offsets VsyncModulator::updateOffsetsLocked() {
- const Offsets& offsets = getNextOffsets();
- mOffsets = offsets;
+VsyncModulator::VsyncConfig VsyncModulator::updateVsyncConfigLocked() {
+ const VsyncConfig& offsets = getNextVsyncConfig();
+ mVsyncConfig = offsets;
if (mTraceDetailedInfo) {
- const bool isEarly = &offsets == &mOffsetsConfig.early;
- const bool isEarlyGpu = &offsets == &mOffsetsConfig.earlyGpu;
- const bool isLate = &offsets == &mOffsetsConfig.late;
+ const bool isEarly = &offsets == &mVsyncConfigSet.early;
+ const bool isEarlyGpu = &offsets == &mVsyncConfigSet.earlyGpu;
+ const bool isLate = &offsets == &mVsyncConfigSet.late;
ATRACE_INT("Vsync-EarlyOffsetsOn", isEarly);
ATRACE_INT("Vsync-EarlyGpuOffsetsOn", isEarlyGpu);
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.h b/services/surfaceflinger/Scheduler/VsyncModulator.h
index f920bd2..355a14a 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.h
@@ -48,62 +48,69 @@
// This may keep early offsets for an extra frame, but avoids a race with transaction commit.
static const std::chrono::nanoseconds MIN_EARLY_TRANSACTION_TIME;
- // Phase offsets for SF and app deadlines from VSYNC.
- struct Offsets {
- nsecs_t sf;
- nsecs_t app;
+ // Phase offsets and work durations for SF and app deadlines from VSYNC.
+ struct VsyncConfig {
+ nsecs_t sfOffset;
+ nsecs_t appOffset;
+ std::chrono::nanoseconds sfWorkDuration;
+ std::chrono::nanoseconds appWorkDuration;
- bool operator==(const Offsets& other) const { return sf == other.sf && app == other.app; }
- bool operator!=(const Offsets& other) const { return !(*this == other); }
+ bool operator==(const VsyncConfig& other) const {
+ return sfOffset == other.sfOffset && appOffset == other.appOffset &&
+ sfWorkDuration == other.sfWorkDuration &&
+ appWorkDuration == other.appWorkDuration;
+ }
+
+ bool operator!=(const VsyncConfig& other) const { return !(*this == other); }
};
- using OffsetsOpt = std::optional<Offsets>;
+ using VsyncConfigOpt = std::optional<VsyncConfig>;
- struct OffsetsConfig {
- Offsets early; // Used for early transactions, and during refresh rate change.
- Offsets earlyGpu; // Used during GPU composition.
- Offsets late; // Default.
+ struct VsyncConfigSet {
+ VsyncConfig early; // Used for early transactions, and during refresh rate change.
+ VsyncConfig earlyGpu; // Used during GPU composition.
+ VsyncConfig late; // Default.
- bool operator==(const OffsetsConfig& other) const {
+ bool operator==(const VsyncConfigSet& other) const {
return early == other.early && earlyGpu == other.earlyGpu && late == other.late;
}
- bool operator!=(const OffsetsConfig& other) const { return !(*this == other); }
+ bool operator!=(const VsyncConfigSet& other) const { return !(*this == other); }
};
using Clock = std::chrono::steady_clock;
using TimePoint = Clock::time_point;
using Now = TimePoint (*)();
- explicit VsyncModulator(const OffsetsConfig&, Now = Clock::now);
+ explicit VsyncModulator(const VsyncConfigSet&, Now = Clock::now);
- Offsets getOffsets() const EXCLUDES(mMutex);
+ VsyncConfig getVsyncConfig() const EXCLUDES(mMutex);
- [[nodiscard]] Offsets setPhaseOffsets(const OffsetsConfig&) EXCLUDES(mMutex);
+ [[nodiscard]] VsyncConfig setVsyncConfigSet(const VsyncConfigSet&) EXCLUDES(mMutex);
// Changes offsets in response to transaction flags or commit.
- [[nodiscard]] OffsetsOpt setTransactionSchedule(TransactionSchedule);
- [[nodiscard]] OffsetsOpt onTransactionCommit();
+ [[nodiscard]] VsyncConfigOpt setTransactionSchedule(TransactionSchedule);
+ [[nodiscard]] VsyncConfigOpt onTransactionCommit();
// Called when we send a refresh rate change to hardware composer, so that
// we can move into early offsets.
- [[nodiscard]] OffsetsOpt onRefreshRateChangeInitiated();
+ [[nodiscard]] VsyncConfigOpt onRefreshRateChangeInitiated();
// Called when we detect from VSYNC signals that the refresh rate changed.
// This way we can move out of early offsets if no longer necessary.
- [[nodiscard]] OffsetsOpt onRefreshRateChangeCompleted();
+ [[nodiscard]] VsyncConfigOpt onRefreshRateChangeCompleted();
- [[nodiscard]] OffsetsOpt onDisplayRefresh(bool usedGpuComposition);
+ [[nodiscard]] VsyncConfigOpt onDisplayRefresh(bool usedGpuComposition);
private:
- const Offsets& getNextOffsets() const REQUIRES(mMutex);
- [[nodiscard]] Offsets updateOffsets() EXCLUDES(mMutex);
- [[nodiscard]] Offsets updateOffsetsLocked() REQUIRES(mMutex);
+ const VsyncConfig& getNextVsyncConfig() const REQUIRES(mMutex);
+ [[nodiscard]] VsyncConfig updateVsyncConfig() EXCLUDES(mMutex);
+ [[nodiscard]] VsyncConfig updateVsyncConfigLocked() REQUIRES(mMutex);
mutable std::mutex mMutex;
- OffsetsConfig mOffsetsConfig GUARDED_BY(mMutex);
+ VsyncConfigSet mVsyncConfigSet GUARDED_BY(mMutex);
- Offsets mOffsets GUARDED_BY(mMutex){mOffsetsConfig.late};
+ VsyncConfig mVsyncConfig GUARDED_BY(mMutex){mVsyncConfigSet.late};
using Schedule = TransactionSchedule;
std::atomic<Schedule> mTransactionSchedule = Schedule::Late;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9a86625..bd43b77 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -947,9 +947,10 @@
const nsecs_t period = hwConfig->getVsyncPeriod();
config.refreshRate = 1e9f / period;
- const auto offsets = mPhaseConfiguration->getOffsetsForRefreshRate(config.refreshRate);
- config.appVsyncOffset = offsets.late.app;
- config.sfVsyncOffset = offsets.late.sf;
+ const auto vsyncConfigSet =
+ mVsyncConfiguration->getConfigsForRefreshRate(config.refreshRate);
+ config.appVsyncOffset = vsyncConfigSet.late.appOffset;
+ config.sfVsyncOffset = vsyncConfigSet.late.sfOffset;
config.configGroup = hwConfig->getConfigGroup();
// This is how far in advance a buffer must be queued for
@@ -1788,8 +1789,8 @@
// We are storing the last 2 present fences. If sf's phase offset is to be
// woken up before the actual vsync but targeting the next vsync, we need to check
// fence N-2
- return mVsyncModulator->getOffsets().sf > 0 ? mPreviousPresentFences[0]
- : mPreviousPresentFences[1];
+ return mVsyncModulator->getVsyncConfig().sfOffset > 0 ? mPreviousPresentFences[0]
+ : mPreviousPresentFences[1];
}
bool SurfaceFlinger::previousFramePending(int graceTimeMs) {
@@ -1821,7 +1822,8 @@
mScheduler->getDisplayStatInfo(&stats);
const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime(now);
// Inflate the expected present time if we're targetting the next vsync.
- return mVsyncModulator->getOffsets().sf > 0 ? presentTime : presentTime + stats.vsyncPeriod;
+ return mVsyncModulator->getVsyncConfig().sfOffset > 0 ? presentTime
+ : presentTime + stats.vsyncPeriod;
}
void SurfaceFlinger::onMessageReceived(int32_t what, nsecs_t expectedVSyncTime) {
@@ -2181,12 +2183,12 @@
nsecs_t compositeToPresentLatency) {
// Integer division and modulo round toward 0 not -inf, so we need to
// treat negative and positive offsets differently.
- nsecs_t idealLatency = (mPhaseConfiguration->getCurrentOffsets().late.sf > 0)
+ nsecs_t idealLatency = (mVsyncConfiguration->getCurrentConfigs().late.sfOffset > 0)
? (stats.vsyncPeriod -
- (mPhaseConfiguration->getCurrentOffsets().late.sf % stats.vsyncPeriod))
- : ((-mPhaseConfiguration->getCurrentOffsets().late.sf) % stats.vsyncPeriod);
+ (mVsyncConfiguration->getCurrentConfigs().late.sfOffset % stats.vsyncPeriod))
+ : ((-mVsyncConfiguration->getCurrentConfigs().late.sfOffset) % stats.vsyncPeriod);
- // Just in case mPhaseConfiguration->getCurrentOffsets().late.sf == -vsyncInterval.
+ // Just in case mVsyncConfiguration->getCurrentConfigs().late.sf == -vsyncInterval.
if (idealLatency <= 0) {
idealLatency = stats.vsyncPeriod;
}
@@ -2196,7 +2198,7 @@
// Reducing jitter is important if an app attempts to extrapolate
// something (such as user input) to an accurate diasplay time.
// Snapping also allows an app to precisely calculate
- // mPhaseConfiguration->getCurrentOffsets().late.sf with (presentLatency % interval).
+ // mVsyncConfiguration->getCurrentConfigs().late.sf with (presentLatency % interval).
nsecs_t bias = stats.vsyncPeriod / 2;
int64_t extraVsyncs = (compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod;
nsecs_t snappedCompositeToPresentLatency =
@@ -2975,16 +2977,18 @@
currentConfig, hal::PowerMode::OFF);
mRefreshRateStats->setConfigMode(currentConfig);
- mPhaseConfiguration = getFactory().createPhaseConfiguration(*mRefreshRateConfigs);
- mVsyncModulator.emplace(mPhaseConfiguration->getCurrentOffsets());
+ mVsyncConfiguration = getFactory().createVsyncConfiguration(*mRefreshRateConfigs);
+ mVsyncModulator.emplace(mVsyncConfiguration->getCurrentConfigs());
// start the EventThread
mScheduler = getFactory().createScheduler(*mRefreshRateConfigs, *this);
mAppConnectionHandle =
- mScheduler->createConnection("app", mPhaseConfiguration->getCurrentOffsets().late.app,
+ mScheduler->createConnection("app",
+ mVsyncConfiguration->getCurrentConfigs().late.appOffset,
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
- mScheduler->createConnection("sf", mPhaseConfiguration->getCurrentOffsets().late.sf,
+ mScheduler->createConnection("sf",
+ mVsyncConfiguration->getCurrentConfigs().late.sfOffset,
[this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
});
@@ -3008,13 +3012,13 @@
}
void SurfaceFlinger::updatePhaseConfiguration(const RefreshRate& refreshRate) {
- mPhaseConfiguration->setRefreshRateFps(refreshRate.getFps());
- setPhaseOffsets(mVsyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets()));
+ mVsyncConfiguration->setRefreshRateFps(refreshRate.getFps());
+ setVsyncConfig(mVsyncModulator->setVsyncConfigSet(mVsyncConfiguration->getCurrentConfigs()));
}
-void SurfaceFlinger::setPhaseOffsets(const VsyncModulator::Offsets& offsets) {
- mScheduler->setPhaseOffset(mAppConnectionHandle, offsets.app);
- mScheduler->setPhaseOffset(mSfConnectionHandle, offsets.sf);
+void SurfaceFlinger::setVsyncConfig(const VsyncModulator::VsyncConfig& config) {
+ mScheduler->setPhaseOffset(mAppConnectionHandle, config.appOffset);
+ mScheduler->setPhaseOffset(mSfConnectionHandle, config.sfOffset);
}
void SurfaceFlinger::commitTransaction() {
@@ -4454,7 +4458,7 @@
mRefreshRateStats->dump(result);
result.append("\n");
- mPhaseConfiguration->dump(result);
+ mVsyncConfiguration->dump(result);
StringAppendF(&result,
" present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n",
dispSyncPresentTimeOffset, getVsyncPeriodFromHWC());
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3c24158..24837b8 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -608,7 +608,7 @@
void initScheduler(PhysicalDisplayId primaryDisplayId);
void updatePhaseConfiguration(const RefreshRate&);
- void setPhaseOffsets(const VsyncModulator::Offsets&);
+ void setVsyncConfig(const VsyncModulator::VsyncConfig&);
/* handlePageFlip - latch a new buffer if available and compute the dirty
* region. Returns whether a new buffer has been latched, i.e., whether it
@@ -1214,7 +1214,7 @@
scheduler::ConnectionHandle mSfConnectionHandle;
// Stores phase offsets configured per refresh rate.
- std::unique_ptr<scheduler::PhaseConfiguration> mPhaseConfiguration;
+ std::unique_ptr<scheduler::VsyncConfiguration> mVsyncConfiguration;
// Optional to defer construction until PhaseConfiguration is created.
std::optional<scheduler::VsyncModulator> mVsyncModulator;
@@ -1226,10 +1226,10 @@
hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
template <typename... Args,
- typename Handler = VsyncModulator::OffsetsOpt (VsyncModulator::*)(Args...)>
+ typename Handler = VsyncModulator::VsyncConfigOpt (VsyncModulator::*)(Args...)>
void modulateVsync(Handler handler, Args... args) {
- if (const auto offsets = (*mVsyncModulator.*handler)(args...)) {
- setPhaseOffsets(*offsets);
+ if (const auto config = (*mVsyncModulator.*handler)(args...)) {
+ setVsyncConfig(*config);
}
}
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index f80c804..54ce60e 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -58,10 +58,10 @@
return std::make_unique<android::impl::MessageQueue>();
}
-std::unique_ptr<scheduler::PhaseConfiguration> DefaultFactory::createPhaseConfiguration(
+std::unique_ptr<scheduler::VsyncConfiguration> DefaultFactory::createVsyncConfiguration(
const scheduler::RefreshRateConfigs& refreshRateConfigs) {
if (property_get_bool("debug.sf.use_phase_offsets_as_durations", false)) {
- return std::make_unique<scheduler::impl::PhaseDurations>(refreshRateConfigs);
+ return std::make_unique<scheduler::impl::WorkDuration>(refreshRateConfigs);
} else {
return std::make_unique<scheduler::impl::PhaseOffsets>(refreshRateConfigs);
}
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 1757fa8..04af8b0 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -29,7 +29,7 @@
std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework) override;
std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override;
std::unique_ptr<MessageQueue> createMessageQueue() override;
- std::unique_ptr<scheduler::PhaseConfiguration> createPhaseConfiguration(
+ std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
const scheduler::RefreshRateConfigs&) override;
std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&,
ISchedulerCallback&) override;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 1d710c4..784a77b 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -55,7 +55,7 @@
} // namespace compositionengine
namespace scheduler {
-class PhaseConfiguration;
+class VsyncConfiguration;
class RefreshRateConfigs;
} // namespace scheduler
@@ -70,7 +70,7 @@
virtual std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework) = 0;
virtual std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) = 0;
virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0;
- virtual std::unique_ptr<scheduler::PhaseConfiguration> createPhaseConfiguration(
+ virtual std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
const scheduler::RefreshRateConfigs&) = 0;
virtual std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&,
ISchedulerCallback&) = 0;
diff --git a/services/surfaceflinger/tests/unittests/FakeVsyncConfiguration.h b/services/surfaceflinger/tests/unittests/FakeVsyncConfiguration.h
index d023b97..4cd1e0a 100644
--- a/services/surfaceflinger/tests/unittests/FakeVsyncConfiguration.h
+++ b/services/surfaceflinger/tests/unittests/FakeVsyncConfiguration.h
@@ -22,15 +22,19 @@
namespace android::scheduler {
-struct FakePhaseOffsets : PhaseConfiguration {
+struct FakePhaseOffsets : VsyncConfiguration {
static constexpr nsecs_t FAKE_PHASE_OFFSET_NS = 0;
+ static constexpr auto FAKE_DURATION_OFFSET_NS = std::chrono::nanoseconds(0);
- Offsets getOffsetsForRefreshRate(float) const override { return getCurrentOffsets(); }
+ VsyncConfigSet getConfigsForRefreshRate(float) const override { return getCurrentConfigs(); }
- Offsets getCurrentOffsets() const override {
- return {{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
- {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
- {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}};
+ VsyncConfigSet getCurrentConfigs() const override {
+ return {{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS, FAKE_DURATION_OFFSET_NS,
+ FAKE_DURATION_OFFSET_NS},
+ {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS, FAKE_DURATION_OFFSET_NS,
+ FAKE_DURATION_OFFSET_NS},
+ {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS, FAKE_DURATION_OFFSET_NS,
+ FAKE_DURATION_OFFSET_NS}};
}
void setRefreshRateFps(float) override {}
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 00fe5ff5..a1049d8 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -77,7 +77,7 @@
return std::make_unique<android::impl::MessageQueue>();
}
- std::unique_ptr<scheduler::PhaseConfiguration> createPhaseConfiguration(
+ std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
const scheduler::RefreshRateConfigs& /*refreshRateConfigs*/) override {
return std::make_unique<scheduler::FakePhaseOffsets>();
}
@@ -216,9 +216,9 @@
scheduler::RefreshRateStats>(*mFlinger->mRefreshRateConfigs, *mFlinger->mTimeStats,
/*currentConfig=*/HwcConfigIndexType(0),
/*powerMode=*/hal::PowerMode::OFF);
- mFlinger->mPhaseConfiguration =
- mFactory.createPhaseConfiguration(*mFlinger->mRefreshRateConfigs);
- mFlinger->mVsyncModulator.emplace(mFlinger->mPhaseConfiguration->getCurrentOffsets());
+ mFlinger->mVsyncConfiguration =
+ mFactory.createVsyncConfiguration(*mFlinger->mRefreshRateConfigs);
+ mFlinger->mVsyncModulator.emplace(mFlinger->mVsyncConfiguration->getCurrentConfigs());
constexpr bool kUseContentDetectionV2 = false;
mScheduler =
diff --git a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
index 0c51cfb..72ee6db 100644
--- a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
#undef LOG_TAG
#define LOG_TAG "SchedulerUnittests"
@@ -31,138 +27,280 @@
namespace android::scheduler {
-class TestablePhaseOffsetsAsDurations : public impl::PhaseDurations {
+class TestableWorkDuration : public impl::WorkDuration {
public:
- TestablePhaseOffsetsAsDurations(float currentFps, nsecs_t sfDuration, nsecs_t appDuration,
- nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
- nsecs_t sfEarlyGlDuration, nsecs_t appEarlyGlDuration)
- : impl::PhaseDurations({60.0f, 90.0f}, currentFps, sfDuration, appDuration,
- sfEarlyDuration, appEarlyDuration, sfEarlyGlDuration,
- appEarlyGlDuration) {}
+ TestableWorkDuration(float currentFps, nsecs_t sfDuration, nsecs_t appDuration,
+ nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
+ nsecs_t sfEarlyGlDuration, nsecs_t appEarlyGlDuration)
+ : impl::WorkDuration({60.0f, 90.0f}, currentFps, sfDuration, appDuration, sfEarlyDuration,
+ appEarlyDuration, sfEarlyGlDuration, appEarlyGlDuration) {}
};
-class PhaseDurationTest : public testing::Test {
+class WorkDurationTest : public testing::Test {
protected:
- PhaseDurationTest()
- : mPhaseDurations(60.0f, 10'500'000, 20'500'000, 16'000'000, 16'500'000, 13'500'000,
- 21'000'000) {}
+ WorkDurationTest()
+ : mWorkDuration(60.0f, 10'500'000, 20'500'000, 16'000'000, 16'500'000, 13'500'000,
+ 21'000'000) {}
- ~PhaseDurationTest() = default;
+ ~WorkDurationTest() = default;
- TestablePhaseOffsetsAsDurations mPhaseDurations;
+ TestableWorkDuration mWorkDuration;
};
/* ------------------------------------------------------------------------
* Test cases
*/
-TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_60Hz) {
- mPhaseDurations.setRefreshRateFps(60.0f);
- auto currentOffsets = mPhaseDurations.getCurrentOffsets();
- auto offsets = mPhaseDurations.getOffsetsForRefreshRate(60.0f);
+TEST_F(WorkDurationTest, getConfigsForRefreshRate_60Hz) {
+ mWorkDuration.setRefreshRateFps(60.0f);
+ auto currentOffsets = mWorkDuration.getCurrentConfigs();
+ auto offsets = mWorkDuration.getConfigsForRefreshRate(60.0f);
EXPECT_EQ(currentOffsets, offsets);
- EXPECT_EQ(offsets.late.sf, 6'166'667);
+ EXPECT_EQ(offsets.late.sfOffset, 6'166'667);
+ EXPECT_EQ(offsets.late.appOffset, 2'333'334);
- EXPECT_EQ(offsets.late.app, 2'333'334);
+ EXPECT_EQ(offsets.late.sfWorkDuration, 10'500'000ns);
+ EXPECT_EQ(offsets.late.appWorkDuration, 20'500'000ns);
- EXPECT_EQ(offsets.early.sf, 666'667);
+ EXPECT_EQ(offsets.early.sfOffset, 666'667);
+ EXPECT_EQ(offsets.early.appOffset, 833'334);
- EXPECT_EQ(offsets.early.app, 833'334);
+ EXPECT_EQ(offsets.early.sfWorkDuration, 16'000'000ns);
+ EXPECT_EQ(offsets.early.appWorkDuration, 16'500'000ns);
- EXPECT_EQ(offsets.earlyGpu.sf, 3'166'667);
+ EXPECT_EQ(offsets.earlyGpu.sfOffset, 3'166'667);
+ EXPECT_EQ(offsets.earlyGpu.appOffset, 15'500'001);
- EXPECT_EQ(offsets.earlyGpu.app, 15'500'001);
+ EXPECT_EQ(offsets.earlyGpu.sfWorkDuration, 13'500'000ns);
+ EXPECT_EQ(offsets.earlyGpu.appWorkDuration, 21'000'000ns);
}
-TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_90Hz) {
- mPhaseDurations.setRefreshRateFps(90.0f);
- auto currentOffsets = mPhaseDurations.getCurrentOffsets();
- auto offsets = mPhaseDurations.getOffsetsForRefreshRate(90.0f);
+TEST_F(WorkDurationTest, getConfigsForRefreshRate_90Hz) {
+ mWorkDuration.setRefreshRateFps(90.0f);
+ auto currentOffsets = mWorkDuration.getCurrentConfigs();
+ auto offsets = mWorkDuration.getConfigsForRefreshRate(90.0f);
EXPECT_EQ(currentOffsets, offsets);
- EXPECT_EQ(offsets.late.sf, 611'111);
+ EXPECT_EQ(offsets.late.sfOffset, 611'111);
+ EXPECT_EQ(offsets.late.appOffset, 2'333'333);
- EXPECT_EQ(offsets.late.app, 2'333'333);
+ EXPECT_EQ(offsets.late.sfWorkDuration, 10'500'000ns);
+ EXPECT_EQ(offsets.late.appWorkDuration, 20'500'000ns);
- EXPECT_EQ(offsets.early.sf, -4'888'889);
+ EXPECT_EQ(offsets.early.sfOffset, -4'888'889);
+ EXPECT_EQ(offsets.early.appOffset, 833'333);
- EXPECT_EQ(offsets.early.app, 833'333);
+ EXPECT_EQ(offsets.early.sfWorkDuration, 16'000'000ns);
+ EXPECT_EQ(offsets.early.appWorkDuration, 16'500'000ns);
- EXPECT_EQ(offsets.earlyGpu.sf, -2'388'889);
+ EXPECT_EQ(offsets.earlyGpu.sfOffset, -2'388'889);
+ EXPECT_EQ(offsets.earlyGpu.appOffset, 9'944'444);
- EXPECT_EQ(offsets.earlyGpu.app, 9'944'444);
+ EXPECT_EQ(offsets.earlyGpu.sfWorkDuration, 13'500'000ns);
+ EXPECT_EQ(offsets.earlyGpu.appWorkDuration, 21'000'000ns);
}
-TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_DefaultOffsets) {
- TestablePhaseOffsetsAsDurations phaseOffsetsWithDefaultValues(60.0f, -1, -1, -1, -1, -1, -1);
+TEST_F(WorkDurationTest, getConfigsForRefreshRate_DefaultOffsets) {
+ TestableWorkDuration phaseOffsetsWithDefaultValues(60.0f, -1, -1, -1, -1, -1, -1);
- auto validateOffsets = [](auto& offsets) {
- EXPECT_EQ(offsets.late.sf, 1'000'000);
+ auto validateOffsets = [](const auto& offsets, std::chrono::nanoseconds vsyncPeriod) {
+ EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
+ EXPECT_EQ(offsets.late.appOffset, 1'000'000);
- EXPECT_EQ(offsets.late.app, 1'000'000);
+ EXPECT_EQ(offsets.late.sfWorkDuration, vsyncPeriod - 1'000'000ns);
+ EXPECT_EQ(offsets.late.appWorkDuration, vsyncPeriod);
- EXPECT_EQ(offsets.early.sf, 1'000'000);
+ EXPECT_EQ(offsets.early.sfOffset, 1'000'000);
+ EXPECT_EQ(offsets.early.appOffset, 1'000'000);
- EXPECT_EQ(offsets.early.app, 1'000'000);
+ EXPECT_EQ(offsets.early.sfWorkDuration, vsyncPeriod - 1'000'000ns);
+ EXPECT_EQ(offsets.early.appWorkDuration, vsyncPeriod);
- EXPECT_EQ(offsets.earlyGpu.sf, 1'000'000);
+ EXPECT_EQ(offsets.earlyGpu.sfOffset, 1'000'000);
+ EXPECT_EQ(offsets.earlyGpu.appOffset, 1'000'000);
- EXPECT_EQ(offsets.earlyGpu.app, 1'000'000);
+ EXPECT_EQ(offsets.earlyGpu.sfWorkDuration, vsyncPeriod - 1'000'000ns);
+ EXPECT_EQ(offsets.earlyGpu.appWorkDuration, vsyncPeriod);
};
- phaseOffsetsWithDefaultValues.setRefreshRateFps(90.0f);
- auto currentOffsets = phaseOffsetsWithDefaultValues.getCurrentOffsets();
- auto offsets = phaseOffsetsWithDefaultValues.getOffsetsForRefreshRate(90.0f);
- EXPECT_EQ(currentOffsets, offsets);
- validateOffsets(offsets);
-
- phaseOffsetsWithDefaultValues.setRefreshRateFps(60.0f);
- currentOffsets = phaseOffsetsWithDefaultValues.getCurrentOffsets();
- offsets = phaseOffsetsWithDefaultValues.getOffsetsForRefreshRate(90.0f);
- EXPECT_EQ(currentOffsets, offsets);
- validateOffsets(offsets);
-}
-
-TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_unknownRefreshRate) {
- auto offsets = mPhaseDurations.getOffsetsForRefreshRate(14.7f);
-
- EXPECT_EQ(offsets.late.sf, 57'527'208);
-
- EXPECT_EQ(offsets.late.app, 37'027'208);
-
- EXPECT_EQ(offsets.early.sf, 52'027'208);
-
- EXPECT_EQ(offsets.early.app, 35'527'208);
-
- EXPECT_EQ(offsets.earlyGpu.sf, 54'527'208);
-
- EXPECT_EQ(offsets.earlyGpu.app, 33'527'208);
-}
-
-TEST(PhaseOffsetsTest, getOffsetsForRefreshRate_unknownRefreshRate) {
- struct PhaseOffsets : impl::PhaseOffsets {
- using impl::PhaseOffsets::PhaseOffsets;
- static PhaseOffsets get() {
- return {{60.0f, 90.0f}, 60.0f, 1'000'000, 1'000'000, {}, {}, {}, {}, 10'000'000};
- }
+ const auto testForRefreshRate = [&](float refreshRate) {
+ phaseOffsetsWithDefaultValues.setRefreshRateFps(refreshRate);
+ auto currentOffsets = phaseOffsetsWithDefaultValues.getCurrentConfigs();
+ auto offsets = phaseOffsetsWithDefaultValues.getConfigsForRefreshRate(refreshRate);
+ EXPECT_EQ(currentOffsets, offsets);
+ validateOffsets(offsets,
+ std::chrono::nanoseconds(static_cast<nsecs_t>(1e9f / refreshRate)));
};
- auto offsets = PhaseOffsets::get().getOffsetsForRefreshRate(14.7f);
+ testForRefreshRate(90.0f);
+ testForRefreshRate(60.0f);
+}
- EXPECT_EQ(offsets.late.sf, 1'000'000);
+TEST_F(WorkDurationTest, getConfigsForRefreshRate_unknownRefreshRate) {
+ auto offsets = mWorkDuration.getConfigsForRefreshRate(14.7f);
- EXPECT_EQ(offsets.late.app, 1'000'000);
+ EXPECT_EQ(offsets.late.sfOffset, 57'527'208);
+ EXPECT_EQ(offsets.late.appOffset, 37'027'208);
- EXPECT_EQ(offsets.early.sf, 1'000'000);
+ EXPECT_EQ(offsets.late.sfWorkDuration, 10'500'000ns);
+ EXPECT_EQ(offsets.late.appWorkDuration, 20'500'000ns);
- EXPECT_EQ(offsets.early.app, 1'000'000);
+ EXPECT_EQ(offsets.early.sfOffset, 52'027'208);
+ EXPECT_EQ(offsets.early.appOffset, 35'527'208);
- EXPECT_EQ(offsets.earlyGpu.sf, 1'000'000);
+ EXPECT_EQ(offsets.early.sfWorkDuration, 16'000'000ns);
+ EXPECT_EQ(offsets.early.appWorkDuration, 16'500'000ns);
- EXPECT_EQ(offsets.earlyGpu.app, 1'000'000);
+ EXPECT_EQ(offsets.earlyGpu.sfOffset, 54'527'208);
+ EXPECT_EQ(offsets.earlyGpu.appOffset, 33'527'208);
+
+ EXPECT_EQ(offsets.earlyGpu.sfWorkDuration, 13'500'000ns);
+ EXPECT_EQ(offsets.earlyGpu.appWorkDuration, 21'000'000ns);
+}
+
+class TestablePhaseOffsets : public impl::PhaseOffsets {
+public:
+ TestablePhaseOffsets(nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs,
+ std::optional<nsecs_t> earlySfOffsetNs,
+ std::optional<nsecs_t> earlyGpuSfOffsetNs,
+ std::optional<nsecs_t> earlyAppOffsetNs,
+ std::optional<nsecs_t> earlyGpuAppOffsetNs,
+ nsecs_t highFpsVsyncPhaseOffsetNs, nsecs_t highFpsSfVSyncPhaseOffsetNs,
+ std::optional<nsecs_t> highFpsEarlySfOffsetNs,
+ std::optional<nsecs_t> highFpsEarlyGpuSfOffsetNs,
+ std::optional<nsecs_t> highFpsEarlyAppOffsetNs,
+ std::optional<nsecs_t> highFpsEarlyGpuAppOffsetNs,
+ nsecs_t thresholdForNextVsync)
+ : impl::PhaseOffsets({60.0f, 90.0f}, 60.0f, vsyncPhaseOffsetNs, sfVSyncPhaseOffsetNs,
+ earlySfOffsetNs, earlyGpuSfOffsetNs, earlyAppOffsetNs,
+ earlyGpuAppOffsetNs, highFpsVsyncPhaseOffsetNs,
+ highFpsSfVSyncPhaseOffsetNs, highFpsEarlySfOffsetNs,
+ highFpsEarlyGpuSfOffsetNs, highFpsEarlyAppOffsetNs,
+ highFpsEarlyGpuAppOffsetNs, thresholdForNextVsync) {}
+};
+
+class PhaseOffsetsTest : public testing::Test {
+protected:
+ PhaseOffsetsTest() = default;
+ ~PhaseOffsetsTest() = default;
+
+ TestablePhaseOffsets mPhaseOffsets{2'000'000, 6'000'000, 7'000'000, 8'000'000, 3'000'000,
+ 4'000'000, 2'000'000, 1'000'000, 2'000'000, 3'000'000,
+ 3'000'000, 4'000'000, 10'000'000};
+};
+
+TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_unknownRefreshRate) {
+ auto offsets = mPhaseOffsets.getConfigsForRefreshRate(14.7f);
+
+ EXPECT_EQ(offsets.late.sfOffset, 6'000'000);
+ EXPECT_EQ(offsets.late.appOffset, 2'000'000);
+
+ EXPECT_EQ(offsets.late.sfWorkDuration, 62'027'208ns);
+ EXPECT_EQ(offsets.late.appWorkDuration, 72'027'208ns);
+
+ EXPECT_EQ(offsets.early.sfOffset, 7'000'000);
+ EXPECT_EQ(offsets.early.appOffset, 3'000'000);
+
+ EXPECT_EQ(offsets.early.sfWorkDuration, 61'027'208ns);
+ EXPECT_EQ(offsets.early.appWorkDuration, 72'027'208ns);
+
+ EXPECT_EQ(offsets.earlyGpu.sfOffset, 8'000'000);
+ EXPECT_EQ(offsets.earlyGpu.appOffset, 4'000'000);
+
+ EXPECT_EQ(offsets.earlyGpu.sfWorkDuration, 60'027'208ns);
+ EXPECT_EQ(offsets.earlyGpu.appWorkDuration, 72'027'208ns);
+}
+
+TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_60Hz) {
+ auto offsets = mPhaseOffsets.getConfigsForRefreshRate(60.0f);
+
+ EXPECT_EQ(offsets.late.sfOffset, 6'000'000);
+ EXPECT_EQ(offsets.late.appOffset, 2'000'000);
+
+ EXPECT_EQ(offsets.late.sfWorkDuration, 10'666'667ns);
+ EXPECT_EQ(offsets.late.appWorkDuration, 20'666'667ns);
+
+ EXPECT_EQ(offsets.early.sfOffset, 7'000'000);
+ EXPECT_EQ(offsets.early.appOffset, 3'000'000);
+
+ EXPECT_EQ(offsets.early.sfWorkDuration, 9'666'667ns);
+ EXPECT_EQ(offsets.early.appWorkDuration, 20'666'667ns);
+
+ EXPECT_EQ(offsets.earlyGpu.sfOffset, 8'000'000);
+ EXPECT_EQ(offsets.earlyGpu.appOffset, 4'000'000);
+
+ EXPECT_EQ(offsets.earlyGpu.sfWorkDuration, 8'666'667ns);
+ EXPECT_EQ(offsets.earlyGpu.appWorkDuration, 20'666'667ns);
+}
+
+TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_90Hz) {
+ auto offsets = mPhaseOffsets.getConfigsForRefreshRate(90.0f);
+
+ EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
+ EXPECT_EQ(offsets.late.appOffset, 2'000'000);
+
+ EXPECT_EQ(offsets.late.sfWorkDuration, 10'111'111ns);
+ EXPECT_EQ(offsets.late.appWorkDuration, 21'222'222ns);
+
+ EXPECT_EQ(offsets.early.sfOffset, 2'000'000);
+ EXPECT_EQ(offsets.early.appOffset, 3'000'000);
+
+ EXPECT_EQ(offsets.early.sfWorkDuration, 9'111'111ns);
+ EXPECT_EQ(offsets.early.appWorkDuration, 21'222'222ns);
+
+ EXPECT_EQ(offsets.earlyGpu.sfOffset, 3'000'000);
+ EXPECT_EQ(offsets.earlyGpu.appOffset, 4'000'000);
+
+ EXPECT_EQ(offsets.earlyGpu.sfWorkDuration, 8'111'111ns);
+ EXPECT_EQ(offsets.earlyGpu.appWorkDuration, 21'222'222ns);
+}
+
+TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_DefaultValues_60Hz) {
+ TestablePhaseOffsets phaseOffsets{1'000'000, 1'000'000, {}, {}, {}, {}, 2'000'000,
+ 1'000'000, {}, {}, {}, {}, 10'000'000};
+ auto offsets = phaseOffsets.getConfigsForRefreshRate(60.0f);
+
+ EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
+ EXPECT_EQ(offsets.late.appOffset, 1'000'000);
+
+ EXPECT_EQ(offsets.late.sfWorkDuration, 15'666'667ns);
+ EXPECT_EQ(offsets.late.appWorkDuration, 16'666'667ns);
+
+ EXPECT_EQ(offsets.early.sfOffset, 1'000'000);
+ EXPECT_EQ(offsets.early.appOffset, 1'000'000);
+
+ EXPECT_EQ(offsets.early.sfWorkDuration, 15'666'667ns);
+ EXPECT_EQ(offsets.early.appWorkDuration, 16'666'667ns);
+
+ EXPECT_EQ(offsets.earlyGpu.sfOffset, 1'000'000);
+ EXPECT_EQ(offsets.earlyGpu.appOffset, 1'000'000);
+
+ EXPECT_EQ(offsets.earlyGpu.sfWorkDuration, 15'666'667ns);
+ EXPECT_EQ(offsets.earlyGpu.appWorkDuration, 16'666'667ns);
+}
+
+TEST_F(PhaseOffsetsTest, getConfigsForRefreshRate_DefaultValues_90Hz) {
+ TestablePhaseOffsets phaseOffsets{1'000'000, 1'000'000, {}, {}, {}, {}, 2'000'000,
+ 1'000'000, {}, {}, {}, {}, 10'000'000};
+ auto offsets = phaseOffsets.getConfigsForRefreshRate(90.0f);
+
+ EXPECT_EQ(offsets.late.sfOffset, 1'000'000);
+ EXPECT_EQ(offsets.late.appOffset, 2'000'000);
+
+ EXPECT_EQ(offsets.late.sfWorkDuration, 10'111'111ns);
+ EXPECT_EQ(offsets.late.appWorkDuration, 21'222'222ns);
+
+ EXPECT_EQ(offsets.early.sfOffset, 1'000'000);
+ EXPECT_EQ(offsets.early.appOffset, 2'000'000);
+
+ EXPECT_EQ(offsets.early.sfWorkDuration, 10'111'111ns);
+ EXPECT_EQ(offsets.early.appWorkDuration, 21'222'222ns);
+
+ EXPECT_EQ(offsets.earlyGpu.sfOffset, 1'000'000);
+ EXPECT_EQ(offsets.earlyGpu.appOffset, 2'000'000);
+
+ EXPECT_EQ(offsets.earlyGpu.sfWorkDuration, 10'111'111ns);
+ EXPECT_EQ(offsets.earlyGpu.appWorkDuration, 21'222'222ns);
}
} // namespace android::scheduler
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp b/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp
index d7093c6..106da81 100644
--- a/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VsyncModulatorTest.cpp
@@ -22,13 +22,19 @@
namespace android::scheduler {
class VsyncModulatorTest : public testing::Test {
- enum Offsets {
- SF_LATE,
- APP_LATE,
- SF_EARLY,
- APP_EARLY,
- SF_EARLY_GPU,
- APP_EARLY_GPU,
+ enum {
+ SF_OFFSET_LATE,
+ APP_OFFSET_LATE,
+ SF_DURATION_LATE,
+ APP_DURATION_LATE,
+ SF_OFFSET_EARLY,
+ APP_OFFSET_EARLY,
+ SF_DURATION_EARLY,
+ APP_DURATION_EARLY,
+ SF_OFFSET_EARLY_GPU,
+ APP_OFFSET_EARLY_GPU,
+ SF_DURATION_EARLY_GPU,
+ APP_DURATION_EARLY_GPU,
};
static VsyncModulator::TimePoint Now() {
@@ -41,25 +47,30 @@
VsyncModulator::MIN_EARLY_TRANSACTION_FRAMES;
using Schedule = scheduler::TransactionSchedule;
+ using nanos = std::chrono::nanoseconds;
+ const VsyncModulator::VsyncConfig kEarly{SF_OFFSET_EARLY, APP_OFFSET_EARLY,
+ nanos(SF_DURATION_LATE), nanos(APP_DURATION_LATE)};
+ const VsyncModulator::VsyncConfig kEarlyGpu{SF_OFFSET_EARLY_GPU, APP_OFFSET_EARLY_GPU,
+ nanos(SF_DURATION_EARLY),
+ nanos(APP_DURATION_EARLY)};
+ const VsyncModulator::VsyncConfig kLate{SF_OFFSET_LATE, APP_OFFSET_LATE,
+ nanos(SF_DURATION_EARLY_GPU),
+ nanos(APP_DURATION_EARLY_GPU)};
- const VsyncModulator::Offsets kEarly{SF_EARLY, APP_EARLY};
- const VsyncModulator::Offsets kEarlyGpu{SF_EARLY_GPU, APP_EARLY_GPU};
- const VsyncModulator::Offsets kLate{SF_LATE, APP_LATE};
-
- const VsyncModulator::OffsetsConfig mOffsets = {kEarly, kEarlyGpu, kLate};
+ const VsyncModulator::VsyncConfigSet mOffsets = {kEarly, kEarlyGpu, kLate};
VsyncModulator mVsyncModulator{mOffsets, Now};
- void SetUp() override { EXPECT_EQ(kLate, mVsyncModulator.setPhaseOffsets(mOffsets)); }
+ void SetUp() override { EXPECT_EQ(kLate, mVsyncModulator.setVsyncConfigSet(mOffsets)); }
};
-#define CHECK_COMMIT(result, offsets) \
+#define CHECK_COMMIT(result, configs) \
EXPECT_EQ(result, mVsyncModulator.onTransactionCommit()); \
- EXPECT_EQ(offsets, mVsyncModulator.getOffsets());
+ EXPECT_EQ(configs, mVsyncModulator.getVsyncConfig());
-#define CHECK_REFRESH(N, result, offsets) \
+#define CHECK_REFRESH(N, result, configs) \
for (int i = 0; i < N; i++) { \
EXPECT_EQ(result, mVsyncModulator.onDisplayRefresh(false)); \
- EXPECT_EQ(offsets, mVsyncModulator.getOffsets()); \
+ EXPECT_EQ(configs, mVsyncModulator.getVsyncConfig()); \
}
TEST_F(VsyncModulatorTest, Late) {