SurfaceFlinger: use intended wake up time when calculating next present time
If SurfaceFlinger wakes up too late (due to the main thread being busy)
it may calculate a wrong presentation time as it is based on the wake up time.
Instead, cache the intended wake up time and use it as the base time.
Change-Id: I84c37bd5f164fbdef3151c0898d3cea624cea515
Bug: 154199567
Test: collect systrace for launcher scrolling
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 809a0e5..fc6ccae 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -768,9 +768,8 @@
}
}
-nsecs_t DispSync::computeNextRefresh(int periodOffset) const {
+nsecs_t DispSync::computeNextRefresh(int periodOffset, nsecs_t now) const {
Mutex::Autolock lock(mMutex);
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
nsecs_t phase = mReferenceTime + mPhase;
if (mPeriod == 0) {
return 0;
@@ -837,7 +836,7 @@
StringAppendF(&result, "current monotonic time: %" PRId64 "\n", now);
}
-nsecs_t DispSync::expectedPresentTime() {
+nsecs_t DispSync::expectedPresentTime(nsecs_t now) {
// The HWC doesn't currently have a way to report additional latency.
// Assume that whatever we submit now will appear right after the flip.
// For a smart panel this might be 1. This is expressed in frames,
@@ -846,7 +845,7 @@
const uint32_t hwcLatency = 0;
// Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
- return computeNextRefresh(hwcLatency);
+ return computeNextRefresh(hwcLatency, now);
}
} // namespace impl
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index 2d9afc9..2faa81c 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -58,9 +58,9 @@
nsecs_t lastCallbackTime) = 0;
virtual status_t removeEventListener(Callback* callback, nsecs_t* outLastCallback) = 0;
virtual status_t changePhaseOffset(Callback* callback, nsecs_t phase) = 0;
- virtual nsecs_t computeNextRefresh(int periodOffset) const = 0;
+ virtual nsecs_t computeNextRefresh(int periodOffset, nsecs_t now) const = 0;
virtual void setIgnorePresentFences(bool ignore) = 0;
- virtual nsecs_t expectedPresentTime() = 0;
+ virtual nsecs_t expectedPresentTime(nsecs_t now) = 0;
virtual void dump(std::string& result) const = 0;
@@ -167,7 +167,7 @@
// The periodOffset value can be used to move forward or backward; an
// offset of zero is the next refresh, -1 is the previous refresh, 1 is
// the refresh after next. etc.
- nsecs_t computeNextRefresh(int periodOffset) const override;
+ nsecs_t computeNextRefresh(int periodOffset, nsecs_t now) const override;
// In certain situations the present fences aren't a good indicator of vsync
// time, e.g. when vr flinger is active, or simply aren't available,
@@ -178,7 +178,7 @@
void setIgnorePresentFences(bool ignore) override;
// Determine the expected present time when a buffer acquired now will be displayed.
- nsecs_t expectedPresentTime();
+ nsecs_t expectedPresentTime(nsecs_t now);
// dump appends human-readable debug info to the result string.
void dump(std::string& result) const override;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 005d157..d8a666a 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -62,8 +62,9 @@
}
}
-void MessageQueue::Handler::dispatchInvalidate() {
+void MessageQueue::Handler::dispatchInvalidate(nsecs_t timestamp) {
if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) {
+ mLastVsyncTime = timestamp;
mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
}
}
@@ -72,11 +73,11 @@
switch (message.what) {
case INVALIDATE:
android_atomic_and(~eventMaskInvalidate, &mEventMask);
- mQueue.mFlinger->onMessageReceived(message.what);
+ mQueue.mFlinger->onMessageReceived(message.what, mLastVsyncTime);
break;
case REFRESH:
android_atomic_and(~eventMaskRefresh, &mEventMask);
- mQueue.mFlinger->onMessageReceived(message.what);
+ mQueue.mFlinger->onMessageReceived(message.what, mLastVsyncTime);
break;
}
}
@@ -151,7 +152,7 @@
while ((n = DisplayEventReceiver::getEvents(&mEventTube, buffer, 8)) > 0) {
for (int i = 0; i < n; i++) {
if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
- mHandler->dispatchInvalidate();
+ mHandler->dispatchInvalidate(buffer[i].header.timestamp);
break;
}
}
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index fcfc4aa..dbd5e96 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -101,12 +101,13 @@
enum { eventMaskInvalidate = 0x1, eventMaskRefresh = 0x2, eventMaskTransaction = 0x4 };
MessageQueue& mQueue;
int32_t mEventMask;
+ std::atomic<nsecs_t> mLastVsyncTime;
public:
explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) {}
virtual void handleMessage(const Message& message);
void dispatchRefresh();
- void dispatchInvalidate();
+ void dispatchInvalidate(nsecs_t timestamp);
};
friend class Handler;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 9a9523f..5abb0d6 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -250,7 +250,7 @@
}
void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) {
- stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
+ stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0, systemTime());
stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
}
@@ -378,8 +378,8 @@
mPrimaryDispSync->setIgnorePresentFences(ignore);
}
-nsecs_t Scheduler::getDispSyncExpectedPresentTime() {
- return mPrimaryDispSync->expectedPresentTime();
+nsecs_t Scheduler::getDispSyncExpectedPresentTime(nsecs_t now) {
+ return mPrimaryDispSync->expectedPresentTime(now);
}
void Scheduler::registerLayer(Layer* layer) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 04cc96a..d36b16a 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -114,7 +114,7 @@
bool* periodFlushed);
void addPresentFence(const std::shared_ptr<FenceTime>&);
void setIgnorePresentFences(bool ignore);
- nsecs_t getDispSyncExpectedPresentTime();
+ nsecs_t getDispSyncExpectedPresentTime(nsecs_t now);
// Layers are registered on creation, and unregistered when the weak reference expires.
void registerLayer(Layer*);
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index 892ae62..2f1faac 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -221,14 +221,13 @@
}
}
-nsecs_t VSyncReactor::computeNextRefresh(int periodOffset) const {
- auto const now = mClock->now();
+nsecs_t VSyncReactor::computeNextRefresh(int periodOffset, nsecs_t now) const {
auto const currentPeriod = periodOffset ? mTracker->currentPeriod() : 0;
return mTracker->nextAnticipatedVSyncTimeFrom(now + periodOffset * currentPeriod);
}
-nsecs_t VSyncReactor::expectedPresentTime() {
- return mTracker->nextAnticipatedVSyncTimeFrom(mClock->now());
+nsecs_t VSyncReactor::expectedPresentTime(nsecs_t now) {
+ return mTracker->nextAnticipatedVSyncTimeFrom(now);
}
void VSyncReactor::startPeriodTransition(nsecs_t newPeriod) {
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index 5ee29f8..31ddf5a 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -42,8 +42,8 @@
bool addPresentFence(const std::shared_ptr<FenceTime>& fence) final;
void setIgnorePresentFences(bool ignoration) final;
- nsecs_t computeNextRefresh(int periodOffset) const final;
- nsecs_t expectedPresentTime() final;
+ nsecs_t computeNextRefresh(int periodOffset, nsecs_t now) const final;
+ nsecs_t expectedPresentTime(nsecs_t now) final;
void setPeriod(nsecs_t period) final;
nsecs_t getPeriod() final;