SF: Move some Scheduler APIs to VsyncSchedule
Scheduler::getDisplayStatInfo forces callers to query both the deadline
and period, so split it into two VsyncSchedule APIs. Inline Scheduler::
getPreviousVsyncFrom.
Introduce <scheduler/Time.h> for type-safe, self-documenting wrappers
around std::chrono, which will gradually supersede nsecs_t (including
<scheduler/Fps.h> integration).
Clean up SF helpers for previous present fences. Remove the unnecessary
and inaccurate CompositorTiming initialization.
Bug: 185535769
Test: Perfetto timeline is green.
Change-Id: I22d8ad44ae37612e66f9d98fd4e7e1831951eb99
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index bbf4667..00250be 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -28,7 +28,6 @@
#include <ftl/fake_guard.h>
#include <gui/WindowInfo.h>
#include <system/window.h>
-#include <ui/DisplayStatInfo.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
@@ -172,8 +171,7 @@
impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const {
return [this](uid_t uid) {
const Fps refreshRate = holdRefreshRateConfigs()->getActiveMode()->getFps();
- const auto currentPeriod =
- mVsyncSchedule->getTracker().currentPeriod() ?: refreshRate.getPeriodNsecs();
+ const nsecs_t currentPeriod = mVsyncSchedule->period().ns() ?: refreshRate.getPeriodNsecs();
const auto frameRate = getFrameRateOverride(uid);
if (!frameRate.has_value()) {
@@ -361,12 +359,6 @@
thread->setDuration(workDuration, readyDuration);
}
-DisplayStatInfo Scheduler::getDisplayStatInfo(nsecs_t now) {
- const auto vsyncTime = mVsyncSchedule->getTracker().nextAnticipatedVSyncTimeFrom(now);
- const auto vsyncPeriod = mVsyncSchedule->getTracker().currentPeriod();
- return DisplayStatInfo{.vsyncTime = vsyncTime, .vsyncPeriod = vsyncPeriod};
-}
-
ConnectionHandle Scheduler::enableVSyncInjection(bool enable) {
if (mInjectVSyncs == enable) {
return {};
@@ -776,11 +768,4 @@
mFrameRateOverrideMappings.setPreferredRefreshRateForUid(frameRateOverride);
}
-std::chrono::steady_clock::time_point Scheduler::getPreviousVsyncFrom(
- nsecs_t expectedPresentTime) const {
- const auto presentTime = std::chrono::nanoseconds(expectedPresentTime);
- const auto vsyncPeriod = std::chrono::nanoseconds(mVsyncSchedule->getTracker().currentPeriod());
- return std::chrono::steady_clock::time_point(presentTime - vsyncPeriod);
-}
-
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 587a773..444ec2a 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -32,9 +32,8 @@
#include <ui/GraphicTypes.h>
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
-#include <ui/DisplayStatInfo.h>
-
#include <scheduler/Features.h>
+#include <scheduler/Time.h>
#include "EventThread.h"
#include "FrameRateOverrideMappings.h"
@@ -150,8 +149,6 @@
void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration,
std::chrono::nanoseconds readyDuration);
- DisplayStatInfo getDisplayStatInfo(nsecs_t now);
-
// Returns injector handle if injection has toggled, or an invalid handle otherwise.
ConnectionHandle enableVSyncInjection(bool enable);
// Returns false if injection is disabled.
@@ -190,14 +187,12 @@
void setDisplayPowerMode(hal::PowerMode powerMode);
- VSyncDispatch& getVsyncDispatch() { return mVsyncSchedule->getDispatch(); }
+ VsyncSchedule& getVsyncSchedule() { return *mVsyncSchedule; }
// Returns true if a given vsync timestamp is considered valid vsync
// for a given uid
bool isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const;
- std::chrono::steady_clock::time_point getPreviousVsyncFrom(nsecs_t expectedPresentTime) const;
-
void dump(std::string&) const;
void dump(ConnectionHandle, std::string&) const;
void dumpVsync(std::string&) const;
diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
index 3a918a1..95bc31f 100644
--- a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp
@@ -68,6 +68,14 @@
VsyncSchedule::VsyncSchedule(VsyncSchedule&&) = default;
VsyncSchedule::~VsyncSchedule() = default;
+Period VsyncSchedule::period() const {
+ return Period::fromNs(mTracker->currentPeriod());
+}
+
+TimePoint VsyncSchedule::vsyncDeadlineAfter(TimePoint timePoint) const {
+ return TimePoint::fromNs(mTracker->nextAnticipatedVSyncTimeFrom(timePoint.ns()));
+}
+
void VsyncSchedule::dump(std::string& out) const {
out.append("VsyncController:\n");
mController->dump(out);
diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.h b/services/surfaceflinger/Scheduler/VsyncSchedule.h
index 0d9b114..8c17409 100644
--- a/services/surfaceflinger/Scheduler/VsyncSchedule.h
+++ b/services/surfaceflinger/Scheduler/VsyncSchedule.h
@@ -20,6 +20,7 @@
#include <string>
#include <scheduler/Features.h>
+#include <scheduler/Time.h>
namespace android::scheduler {
@@ -38,6 +39,9 @@
VsyncSchedule(VsyncSchedule&&);
~VsyncSchedule();
+ Period period() const;
+ TimePoint vsyncDeadlineAfter(TimePoint) const;
+
// TODO(b/185535769): Hide behind API.
const VsyncTracker& getTracker() const { return *mTracker; }
VsyncTracker& getTracker() { return *mTracker; }
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Time.h b/services/surfaceflinger/Scheduler/include/scheduler/Time.h
new file mode 100644
index 0000000..6fa548e
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/include/scheduler/Time.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <chrono>
+
+#include <utils/Timers.h>
+
+namespace android {
+namespace scheduler {
+
+// TODO(b/185535769): Pull Clock.h to libscheduler to reuse this.
+using SchedulerClock = std::chrono::high_resolution_clock;
+static_assert(SchedulerClock::is_steady);
+
+} // namespace scheduler
+
+struct Duration;
+
+struct TimePoint : scheduler::SchedulerClock::time_point {
+ explicit TimePoint(const Duration&);
+
+ // Implicit conversion from std::chrono counterpart.
+ constexpr TimePoint(scheduler::SchedulerClock::time_point p)
+ : scheduler::SchedulerClock::time_point(p) {}
+
+ static TimePoint fromNs(nsecs_t);
+
+ nsecs_t ns() const;
+};
+
+struct Duration : TimePoint::duration {
+ // Implicit conversion from std::chrono counterpart.
+ constexpr Duration(TimePoint::duration d) : TimePoint::duration(d) {}
+
+ static Duration fromNs(nsecs_t ns) { return {std::chrono::nanoseconds(ns)}; }
+
+ nsecs_t ns() const { return std::chrono::nanoseconds(*this).count(); }
+};
+
+using Period = Duration;
+
+inline TimePoint::TimePoint(const Duration& d) : scheduler::SchedulerClock::time_point(d) {}
+
+inline TimePoint TimePoint::fromNs(nsecs_t ns) {
+ return TimePoint(Duration::fromNs(ns));
+}
+
+inline nsecs_t TimePoint::ns() const {
+ return Duration(time_since_epoch()).ns();
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d313406..65e4b4e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1055,12 +1055,14 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* stats) {
- if (!stats) {
+status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* outStats) {
+ if (!outStats) {
return BAD_VALUE;
}
- *stats = mScheduler->getDisplayStatInfo(systemTime());
+ const auto& schedule = mScheduler->getVsyncSchedule();
+ outStats->vsyncTime = schedule.vsyncDeadlineAfter(scheduler::SchedulerClock::now()).ns();
+ outStats->vsyncPeriod = schedule.period().ns();
return NO_ERROR;
}
@@ -1569,12 +1571,10 @@
status_t SurfaceFlinger::injectVSync(nsecs_t when) {
Mutex::Autolock lock(mStateLock);
- const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(when);
- const auto expectedPresent = calculateExpectedPresentTime(stats);
- return mScheduler->injectVSync(when, /*expectedVSyncTime=*/expectedPresent,
- /*deadlineTimestamp=*/expectedPresent)
- ? NO_ERROR
- : BAD_VALUE;
+ const nsecs_t expectedPresentTime = calculateExpectedPresentTime(when).ns();
+ const nsecs_t deadlineTimestamp = expectedPresentTime;
+ return mScheduler->injectVSync(when, expectedPresentTime, deadlineTimestamp) ? NO_ERROR
+ : BAD_VALUE;
}
status_t SurfaceFlinger::getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers) {
@@ -1951,18 +1951,15 @@
}));
}
-SurfaceFlinger::FenceWithFenceTime SurfaceFlinger::previousFrameFence() {
- const auto now = systemTime();
- const auto vsyncPeriod = mScheduler->getDisplayStatInfo(now).vsyncPeriod;
- const bool expectedPresentTimeIsTheNextVsync = mExpectedPresentTime - now <= vsyncPeriod;
- return expectedPresentTimeIsTheNextVsync ? mPreviousPresentFences[0]
- : mPreviousPresentFences[1];
+auto SurfaceFlinger::getPreviousPresentFence(nsecs_t frameTime, Period vsyncPeriod)
+ -> const FenceTimePtr& {
+ const bool isTwoVsyncsAhead = mExpectedPresentTime - frameTime > vsyncPeriod.ns();
+ const size_t i = static_cast<size_t>(isTwoVsyncsAhead);
+ return mPreviousPresentFences[i].fenceTime;
}
-bool SurfaceFlinger::previousFramePending(int graceTimeMs) {
+bool SurfaceFlinger::isFencePending(const FenceTimePtr& fence, int graceTimeMs) {
ATRACE_CALL();
- const std::shared_ptr<FenceTime>& fence = previousFrameFence().fenceTime;
-
if (fence == FenceTime::NO_FENCE) {
return false;
}
@@ -1973,37 +1970,32 @@
return status == -ETIME;
}
-nsecs_t SurfaceFlinger::previousFramePresentTime() {
- const std::shared_ptr<FenceTime>& fence = previousFrameFence().fenceTime;
+TimePoint SurfaceFlinger::calculateExpectedPresentTime(nsecs_t frameTime) const {
+ const auto& schedule = mScheduler->getVsyncSchedule();
- if (fence == FenceTime::NO_FENCE) {
- return Fence::SIGNAL_TIME_INVALID;
+ const TimePoint vsyncDeadline = schedule.vsyncDeadlineAfter(TimePoint::fromNs(frameTime));
+ if (mVsyncModulator->getVsyncConfig().sfOffset > 0) {
+ return vsyncDeadline;
}
- return fence->getSignalTime();
-}
-
-nsecs_t SurfaceFlinger::calculateExpectedPresentTime(DisplayStatInfo stats) const {
- // Inflate the expected present time if we're targetting the next vsync.
- return mVsyncModulator->getVsyncConfig().sfOffset > 0 ? stats.vsyncTime
- : stats.vsyncTime + stats.vsyncPeriod;
+ // Inflate the expected present time if we're targeting the next vsync.
+ return vsyncDeadline + schedule.period();
}
bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime)
FTL_FAKE_GUARD(kMainThreadContext) {
- // calculate the expected present time once and use the cached
- // value throughout this frame to make sure all layers are
- // seeing this same value.
- if (expectedVsyncTime >= frameTime) {
- mExpectedPresentTime = expectedVsyncTime;
- } else {
- const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(frameTime);
- mExpectedPresentTime = calculateExpectedPresentTime(stats);
- }
-
+ // The expectedVsyncTime, which was predicted when this frame was scheduled, is normally in the
+ // future relative to frameTime, but may not be for delayed frames. Adjust mExpectedPresentTime
+ // accordingly, but not mScheduledPresentTime.
const nsecs_t lastScheduledPresentTime = mScheduledPresentTime;
mScheduledPresentTime = expectedVsyncTime;
+ // Calculate the expected present time once and use the cached value throughout this frame to
+ // make sure all layers are seeing this same value.
+ mExpectedPresentTime = expectedVsyncTime >= frameTime
+ ? expectedVsyncTime
+ : calculateExpectedPresentTime(frameTime).ns();
+
const auto vsyncIn = [&] {
if (!ATRACE_ENABLED()) return 0.f;
return (mExpectedPresentTime - systemTime()) / 1e6f;
@@ -2011,6 +2003,9 @@
ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, vsyncId, vsyncIn,
mExpectedPresentTime == expectedVsyncTime ? "" : " (adjusted)");
+ const Period vsyncPeriod = mScheduler->getVsyncSchedule().period();
+ const FenceTimePtr& previousPresentFence = getPreviousPresentFence(frameTime, vsyncPeriod);
+
// When Backpressure propagation is enabled we want to give a small grace period
// for the present fence to fire instead of just giving up on this frame to handle cases
// where present fence is just about to get signaled.
@@ -2019,7 +2014,8 @@
// Pending frames may trigger backpressure propagation.
const TracedOrdinal<bool> framePending = {"PrevFramePending",
- previousFramePending(graceTimeForPresentFenceMs)};
+ isFencePending(previousPresentFence,
+ graceTimeForPresentFenceMs)};
// Frame missed counts for metrics tracking.
// A frame is missed if the prior frame is still pending. If no longer pending,
@@ -2029,9 +2025,8 @@
// Add some slop to correct for drift. This should generally be
// smaller than a typical frame duration, but should not be so small
// that it reports reasonable drift as a missed frame.
- const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(systemTime());
- const nsecs_t frameMissedSlop = stats.vsyncPeriod / 2;
- const nsecs_t previousPresentTime = previousFramePresentTime();
+ const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2;
+ const nsecs_t previousPresentTime = previousPresentFence->getSignalTime();
const TracedOrdinal<bool> frameMissed = {"PrevFrameMissed",
framePending ||
(previousPresentTime >= 0 &&
@@ -2118,7 +2113,7 @@
// Composite if transactions were committed, or if requested by HWC.
bool mustComposite = mMustComposite.exchange(false);
{
- mFrameTimeline->setSfWakeUp(vsyncId, frameTime, Fps::fromPeriodNsecs(stats.vsyncPeriod));
+ mFrameTimeline->setSfWakeUp(vsyncId, frameTime, Fps::fromPeriodNsecs(vsyncPeriod.ns()));
bool needsTraversal = false;
if (clearTransactionFlags(eTransactionFlushNeeded)) {
@@ -2239,7 +2234,9 @@
}
const auto expectedPresentTime = mExpectedPresentTime.load();
- const auto prevVsyncTime = mScheduler->getPreviousVsyncFrom(expectedPresentTime);
+ const auto prevVsyncTime =
+ TimePoint::fromNs(expectedPresentTime) - mScheduler->getVsyncSchedule().period();
+
const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration;
refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration;
refreshArgs.previousPresentFence = mPreviousPresentFences[0].fenceTime;
@@ -2326,11 +2323,11 @@
mLayersPendingRefresh.clear();
}
-void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
- std::shared_ptr<FenceTime>& presentFenceTime) {
+nsecs_t SurfaceFlinger::trackPresentLatency(nsecs_t compositeTime,
+ std::shared_ptr<FenceTime> presentFenceTime) {
// Update queue of past composite+present times and determine the
// most recently known composite to present latency.
- getBE().mCompositePresentTimes.push({compositeTime, presentFenceTime});
+ getBE().mCompositePresentTimes.push({compositeTime, std::move(presentFenceTime)});
nsecs_t compositeToPresentLatency = -1;
while (!getBE().mCompositePresentTimes.empty()) {
SurfaceFlingerBE::CompositePresentTime& cpt = getBE().mCompositePresentTimes.front();
@@ -2349,13 +2346,13 @@
getBE().mCompositePresentTimes.pop();
}
- setCompositorTimingSnapped(stats, compositeToPresentLatency);
+ return compositeToPresentLatency;
}
-void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats,
+void SurfaceFlinger::setCompositorTimingSnapped(nsecs_t vsyncDeadline, nsecs_t vsyncPeriod,
nsecs_t compositeToPresentLatency) {
// Avoid division by 0 by defaulting to 60Hz
- const auto vsyncPeriod = stats.vsyncPeriod ?: (60_Hz).getPeriodNsecs();
+ vsyncPeriod = vsyncPeriod ?: (60_Hz).getPeriodNsecs();
// Integer division and modulo round toward 0 not -inf, so we need to
// treat negative and positive offsets differently.
@@ -2381,7 +2378,7 @@
(extraVsyncs > 0) ? idealLatency + (extraVsyncs * vsyncPeriod) : idealLatency;
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
- getBE().mCompositorTiming.deadline = stats.vsyncTime - idealLatency;
+ getBE().mCompositorTiming.deadline = vsyncDeadline - idealLatency;
getBE().mCompositorTiming.interval = vsyncPeriod;
getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
}
@@ -2470,13 +2467,18 @@
mFrameTimeline->setSfPresent(/* sfPresentTime */ now, mPreviousPresentFences[0].fenceTime,
glCompositionDoneFenceTime);
- const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(now);
-
// We use the CompositionEngine::getLastFrameRefreshTimestamp() which might
// be sampled a little later than when we started doing work for this frame,
- // but that should be okay since updateCompositorTiming has snapping logic.
- updateCompositorTiming(stats, mCompositionEngine->getLastFrameRefreshTimestamp(),
- mPreviousPresentFences[0].fenceTime);
+ // but that should be okay since setCompositorTimingSnapped has snapping logic.
+ const nsecs_t compositeTime = mCompositionEngine->getLastFrameRefreshTimestamp();
+ const nsecs_t presentLatency =
+ trackPresentLatency(compositeTime, mPreviousPresentFences[0].fenceTime);
+
+ const auto& schedule = mScheduler->getVsyncSchedule();
+ const TimePoint vsyncDeadline = schedule.vsyncDeadlineAfter(TimePoint::fromNs(now));
+ const Period vsyncPeriod = schedule.period();
+ setCompositorTimingSnapped(vsyncDeadline.ns(), vsyncPeriod.ns(), presentLatency);
+
CompositorTiming compositorTiming;
{
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
@@ -2593,7 +2595,7 @@
mHasPoweredOff = false;
} else {
nsecs_t elapsedTime = currentTime - getBE().mLastSwapTime;
- size_t numPeriods = static_cast<size_t>(elapsedTime / stats.vsyncPeriod);
+ const size_t numPeriods = static_cast<size_t>(elapsedTime / vsyncPeriod.ns());
if (numPeriods < SurfaceFlingerBE::NUM_BUCKETS - 1) {
getBE().mFrameBuckets[numPeriods] += elapsedTime;
} else {
@@ -3470,8 +3472,8 @@
mInterceptor->saveVSyncEvent(timestamp);
});
- mScheduler->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(),
- configs.late.sfWorkDuration);
+ mScheduler->initVsync(mScheduler->getVsyncSchedule().getDispatch(),
+ *mFrameTimeline->getTokenManager(), configs.late.sfWorkDuration);
mRegionSamplingThread =
new RegionSamplingThread(*this, RegionSamplingThread::EnvironmentTimingTunables());
@@ -3941,10 +3943,10 @@
bool SurfaceFlinger::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const {
// The amount of time SF can delay a frame if it is considered early based
// on the VsyncModulator::VsyncConfig::appWorkDuration
- constexpr static std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms;
+ constexpr std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms;
- const auto currentVsyncPeriod = mScheduler->getDisplayStatInfo(systemTime()).vsyncPeriod;
- const auto earlyLatchVsyncThreshold = currentVsyncPeriod / 2;
+ const nsecs_t currentVsyncPeriod = mScheduler->getVsyncSchedule().period().ns();
+ const nsecs_t earlyLatchVsyncThreshold = currentVsyncPeriod / 2;
const auto prediction = mFrameTimeline->getTokenManager()->getPredictionsForToken(vsyncId);
if (!prediction.has_value()) {
@@ -4839,10 +4841,6 @@
const nsecs_t vsyncPeriod = display->refreshRateConfigs().getActiveMode()->getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
mActiveDisplayTransformHint = display->getTransformHint();
- // Use phase of 0 since phase is not known.
- // Use latency of 0, which will snap to the ideal latency.
- DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod};
- setCompositorTimingSnapped(stats, 0);
}
void SurfaceFlinger::initializeDisplays() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ed6c8ce..f6dbfbf 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -958,10 +958,12 @@
* Compositing
*/
void postComposition();
+
+ // Returns the composite-to-present latency of the latest presented frame.
+ nsecs_t trackPresentLatency(nsecs_t compositeTime, std::shared_ptr<FenceTime> presentFenceTime);
+
void getCompositorTiming(CompositorTiming* compositorTiming);
- void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
- std::shared_ptr<FenceTime>& presentFenceTime);
- void setCompositorTimingSnapped(const DisplayStatInfo& stats,
+ void setCompositorTimingSnapped(nsecs_t vsyncDeadline, nsecs_t vsyncPeriod,
nsecs_t compositeToPresentLatency);
void postFrame() REQUIRES(kMainThreadContext);
@@ -997,31 +999,17 @@
getHwComposer().setVsyncEnabled(id, enabled);
}
- struct FenceWithFenceTime {
- sp<Fence> fence = Fence::NO_FENCE;
- std::shared_ptr<FenceTime> fenceTime = FenceTime::NO_FENCE;
- };
+ using FenceTimePtr = std::shared_ptr<FenceTime>;
- // Gets the fence for the previous frame.
- // Must be called on the main thread.
- FenceWithFenceTime previousFrameFence();
+ const FenceTimePtr& getPreviousPresentFence(nsecs_t frameTime, Period)
+ REQUIRES(kMainThreadContext);
- // Whether the previous frame has not yet been presented to the display.
- // If graceTimeMs is positive, this method waits for at most the provided
- // grace period before reporting if the frame missed.
- // Must be called on the main thread.
- bool previousFramePending(int graceTimeMs = 0);
-
- // Returns the previous time that the frame was presented. If the frame has
- // not been presented yet, then returns Fence::SIGNAL_TIME_PENDING. If there
- // is no pending frame, then returns Fence::SIGNAL_TIME_INVALID.
- // Must be called on the main thread.
- nsecs_t previousFramePresentTime();
+ // Blocks the thread waiting for up to graceTimeMs in case the fence is about to signal.
+ static bool isFencePending(const FenceTimePtr&, int graceTimeMs);
// Calculates the expected present time for this frame. For negative offsets, performs a
// correction using the predicted vsync for the next frame instead.
-
- nsecs_t calculateExpectedPresentTime(DisplayStatInfo) const;
+ TimePoint calculateExpectedPresentTime(nsecs_t frameTime) const;
/*
* Display identification
@@ -1209,7 +1197,7 @@
std::unordered_set<sp<Layer>, SpHash<Layer>> mLayersWithQueuedFrames;
// Tracks layers that need to update a display's dirty region.
std::vector<sp<Layer>> mLayersPendingRefresh;
- std::array<FenceWithFenceTime, 2> mPreviousPresentFences;
+
// True if in the previous frame at least one layer was composed via the GPU.
bool mHadClientComposition = false;
// True if in the previous frame at least one layer was composed via HW Composer.
@@ -1346,6 +1334,12 @@
std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
+ struct FenceWithFenceTime {
+ sp<Fence> fence = Fence::NO_FENCE;
+ FenceTimePtr fenceTime = FenceTime::NO_FENCE;
+ };
+ std::array<FenceWithFenceTime, 2> mPreviousPresentFences;
+
std::atomic<nsecs_t> mExpectedPresentTime = 0;
nsecs_t mScheduledPresentTime = 0;
hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 456a498..b811ea3 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -535,11 +535,6 @@
mFlinger->setVsyncConfig(vsyncConfig, fdp->ConsumeIntegral<nsecs_t>());
}
- void updateCompositorTiming(FuzzedDataProvider *fdp) {
- std::shared_ptr<FenceTime> presentFenceTime = FenceTime::NO_FENCE;
- mFlinger->updateCompositorTiming({}, fdp->ConsumeIntegral<nsecs_t>(), presentFenceTime);
- }
-
void getCompositorTiming() {
CompositorTiming compositorTiming;
mFlinger->getCompositorTiming(&compositorTiming);
@@ -641,9 +636,11 @@
getCompositorTiming();
- updateCompositorTiming(&mFdp);
+ mFlinger->trackPresentLatency(mFdp.ConsumeIntegral<nsecs_t>(), FenceTime::NO_FENCE);
+ mFlinger->setCompositorTimingSnapped(mFdp.ConsumeIntegral<nsecs_t>(),
+ mFdp.ConsumeIntegral<nsecs_t>(),
+ mFdp.ConsumeIntegral<nsecs_t>());
- mFlinger->setCompositorTimingSnapped({}, mFdp.ConsumeIntegral<nsecs_t>());
FTL_FAKE_GUARD(kMainThreadContext, mFlinger->postFrame());
mFlinger->calculateExpectedPresentTime({});
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
index 37cf05e..3d576f4 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
@@ -85,12 +85,6 @@
// The display transaction needed flag should be set.
EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
-
- // The compositor timing should be set to default values
- const auto& compositorTiming = mFlinger.getCompositorTiming();
- EXPECT_EQ(-DEFAULT_VSYNC_PERIOD, compositorTiming.deadline);
- EXPECT_EQ(DEFAULT_VSYNC_PERIOD, compositorTiming.interval);
- EXPECT_EQ(DEFAULT_VSYNC_PERIOD, compositorTiming.presentLatency);
}
} // namespace