SF: Decouple MessageQueue
Define an ICompositor interface against which MessageQueue (which ought
to be an implementation detail of Scheduler) is implemented. Change the
equivocal invalidate/refresh nomenclature to commit/composite. Schedule
sampling only after composite.
Bug: 185535769
Test: libsurfaceflinger_unittest
Change-Id: I0c18f312459bae48531449f24f7b53c104fc5812
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 4d51125..043a536 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -27,49 +27,55 @@
#include "EventThread.h"
#include "FrameTimeline.h"
#include "MessageQueue.h"
-#include "SurfaceFlinger.h"
namespace android::impl {
-void MessageQueue::Handler::dispatchRefresh() {
- if ((mEventMask.fetch_or(eventMaskRefresh) & eventMaskRefresh) == 0) {
- mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
+void MessageQueue::Handler::dispatchComposite() {
+ if ((mEventMask.fetch_or(kComposite) & kComposite) == 0) {
+ mQueue.mLooper->sendMessage(this, Message(kComposite));
}
}
-void MessageQueue::Handler::dispatchInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTimestamp) {
- if ((mEventMask.fetch_or(eventMaskInvalidate) & eventMaskInvalidate) == 0) {
+void MessageQueue::Handler::dispatchCommit(int64_t vsyncId, nsecs_t expectedVsyncTime) {
+ if ((mEventMask.fetch_or(kCommit) & kCommit) == 0) {
mVsyncId = vsyncId;
- mExpectedVSyncTime = expectedVSyncTimestamp;
- mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
+ mExpectedVsyncTime = expectedVsyncTime;
+ mQueue.mLooper->sendMessage(this, Message(kCommit));
}
}
-bool MessageQueue::Handler::invalidatePending() {
- constexpr auto pendingMask = eventMaskInvalidate | eventMaskRefresh;
- return (mEventMask.load() & pendingMask) != 0;
+bool MessageQueue::Handler::isFramePending() const {
+ constexpr auto kPendingMask = kCommit | kComposite;
+ return (mEventMask.load() & kPendingMask) != 0;
}
void MessageQueue::Handler::handleMessage(const Message& message) {
+ const nsecs_t frameTime = systemTime();
switch (message.what) {
- case INVALIDATE:
- mEventMask.fetch_and(~eventMaskInvalidate);
- mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime);
- break;
- case REFRESH:
- mEventMask.fetch_and(~eventMaskRefresh);
- mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime);
+ case kCommit:
+ mEventMask.fetch_and(~kCommit);
+ if (!mQueue.mCompositor.commit(frameTime, mVsyncId, mExpectedVsyncTime)) {
+ return;
+ }
+ // Composite immediately, rather than after pending tasks through scheduleComposite.
+ [[fallthrough]];
+ case kComposite:
+ mEventMask.fetch_and(~kComposite);
+ mQueue.mCompositor.composite(frameTime);
+ mQueue.mCompositor.sample();
break;
}
}
-// ---------------------------------------------------------------------------
+MessageQueue::MessageQueue(ICompositor& compositor)
+ : MessageQueue(compositor, sp<Handler>::make(*this)) {}
-void MessageQueue::init(const sp<SurfaceFlinger>& flinger) {
- mFlinger = flinger;
- mLooper = new Looper(true);
- mHandler = new Handler(*this);
-}
+constexpr bool kAllowNonCallbacks = true;
+
+MessageQueue::MessageQueue(ICompositor& compositor, sp<Handler> handler)
+ : mCompositor(compositor),
+ mLooper(sp<Looper>::make(kAllowNonCallbacks)),
+ mHandler(std::move(handler)) {}
// TODO(b/169865816): refactor VSyncInjections to use MessageQueue directly
// and remove the EventThread from MessageQueue
@@ -110,11 +116,13 @@
{
std::lock_guard lock(mVsync.mutex);
mVsync.lastCallbackTime = std::chrono::nanoseconds(vsyncTime);
- mVsync.scheduled = false;
+ mVsync.scheduledFrameTime.reset();
}
- mHandler->dispatchInvalidate(mVsync.tokenManager->generateTokenForPredictions(
- {targetWakeupTime, readyTime, vsyncTime}),
- vsyncTime);
+
+ const auto vsyncId = mVsync.tokenManager->generateTokenForPredictions(
+ {targetWakeupTime, readyTime, vsyncTime});
+
+ mHandler->dispatchCommit(vsyncId, vsyncTime);
}
void MessageQueue::initVsync(scheduler::VSyncDispatch& dispatch,
@@ -135,8 +143,8 @@
ATRACE_CALL();
std::lock_guard lock(mVsync.mutex);
mVsync.workDuration = workDuration;
- if (mVsync.scheduled) {
- mVsync.expectedWakeupTime = mVsync.registration->schedule(
+ if (mVsync.scheduledFrameTime) {
+ mVsync.scheduledFrameTime = mVsync.registration->schedule(
{mVsync.workDuration.get().count(),
/*readyDuration=*/0, mVsync.lastCallbackTime.count()});
}
@@ -168,7 +176,7 @@
mLooper->sendMessage(handler, Message());
}
-void MessageQueue::invalidate() {
+void MessageQueue::scheduleCommit() {
ATRACE_CALL();
{
@@ -181,15 +189,14 @@
}
std::lock_guard lock(mVsync.mutex);
- mVsync.scheduled = true;
- mVsync.expectedWakeupTime =
+ mVsync.scheduledFrameTime =
mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
.readyDuration = 0,
.earliestVsync = mVsync.lastCallbackTime.count()});
}
-void MessageQueue::refresh() {
- mHandler->dispatchRefresh();
+void MessageQueue::scheduleComposite() {
+ mHandler->dispatchComposite();
}
void MessageQueue::injectorCallback() {
@@ -198,24 +205,22 @@
while ((n = DisplayEventReceiver::getEvents(&mInjector.tube, buffer, 8)) > 0) {
for (int i = 0; i < n; i++) {
if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
- mHandler->dispatchInvalidate(buffer[i].vsync.vsyncId,
- buffer[i].vsync.expectedVSyncTimestamp);
+ mHandler->dispatchCommit(buffer[i].vsync.vsyncId,
+ buffer[i].vsync.expectedVSyncTimestamp);
break;
}
}
}
}
-std::optional<std::chrono::steady_clock::time_point> MessageQueue::nextExpectedInvalidate() {
- if (mHandler->invalidatePending()) {
- return std::chrono::steady_clock::now();
+auto MessageQueue::getScheduledFrameTime() const -> std::optional<Clock::time_point> {
+ if (mHandler->isFramePending()) {
+ return Clock::now();
}
std::lock_guard lock(mVsync.mutex);
- if (mVsync.scheduled) {
- LOG_ALWAYS_FATAL_IF(!mVsync.expectedWakeupTime.has_value(), "callback was never scheduled");
- const auto expectedWakeupTime = std::chrono::nanoseconds(*mVsync.expectedWakeupTime);
- return std::optional<std::chrono::steady_clock::time_point>(expectedWakeupTime);
+ if (const auto time = mVsync.scheduledFrameTime) {
+ return Clock::time_point(std::chrono::nanoseconds(*time));
}
return std::nullopt;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 58ce9b9..2c908a6 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -33,7 +33,14 @@
namespace android {
-class SurfaceFlinger;
+struct ICompositor {
+ virtual bool commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) = 0;
+ virtual void composite(nsecs_t frameTime) = 0;
+ virtual void sample() = 0;
+
+protected:
+ ~ICompositor() = default;
+};
template <typename F>
class Task : public MessageHandler {
@@ -56,65 +63,65 @@
class MessageQueue {
public:
- enum {
- INVALIDATE = 0,
- REFRESH = 1,
- };
-
virtual ~MessageQueue() = default;
- virtual void init(const sp<SurfaceFlinger>& flinger) = 0;
virtual void initVsync(scheduler::VSyncDispatch&, frametimeline::TokenManager&,
std::chrono::nanoseconds workDuration) = 0;
virtual void setDuration(std::chrono::nanoseconds workDuration) = 0;
virtual void setInjector(sp<EventThreadConnection>) = 0;
virtual void waitMessage() = 0;
virtual void postMessage(sp<MessageHandler>&&) = 0;
- virtual void invalidate() = 0;
- virtual void refresh() = 0;
- virtual std::optional<std::chrono::steady_clock::time_point> nextExpectedInvalidate() = 0;
-};
+ virtual void scheduleCommit() = 0;
+ virtual void scheduleComposite() = 0;
-// ---------------------------------------------------------------------------
+ using Clock = std::chrono::steady_clock;
+ virtual std::optional<Clock::time_point> getScheduledFrameTime() const = 0;
+};
namespace impl {
class MessageQueue : public android::MessageQueue {
protected:
class Handler : public MessageHandler {
- enum : uint32_t {
- eventMaskInvalidate = 0x1,
- eventMaskRefresh = 0x2,
- eventMaskTransaction = 0x4
- };
+ static constexpr uint32_t kCommit = 0b1;
+ static constexpr uint32_t kComposite = 0b10;
+
MessageQueue& mQueue;
- std::atomic<uint32_t> mEventMask;
- std::atomic<int64_t> mVsyncId;
- std::atomic<nsecs_t> mExpectedVSyncTime;
+ std::atomic<uint32_t> mEventMask = 0;
+ std::atomic<int64_t> mVsyncId = 0;
+ std::atomic<nsecs_t> mExpectedVsyncTime = 0;
public:
- explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) {}
+ explicit Handler(MessageQueue& queue) : mQueue(queue) {}
void handleMessage(const Message& message) override;
- virtual void dispatchRefresh();
- virtual void dispatchInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTimestamp);
- virtual bool invalidatePending();
+
+ bool isFramePending() const;
+
+ virtual void dispatchCommit(int64_t vsyncId, nsecs_t expectedVsyncTime);
+ void dispatchComposite();
};
friend class Handler;
- sp<SurfaceFlinger> mFlinger;
- sp<Looper> mLooper;
+ // For tests.
+ MessageQueue(ICompositor&, sp<Handler>);
+
+ void vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime);
+
+private:
+ ICompositor& mCompositor;
+ const sp<Looper> mLooper;
+ const sp<Handler> mHandler;
struct Vsync {
frametimeline::TokenManager* tokenManager = nullptr;
std::unique_ptr<scheduler::VSyncCallbackRegistration> registration;
- std::mutex mutex;
+ mutable std::mutex mutex;
TracedOrdinal<std::chrono::nanoseconds> workDuration
GUARDED_BY(mutex) = {"VsyncWorkDuration-sf", std::chrono::nanoseconds(0)};
std::chrono::nanoseconds lastCallbackTime GUARDED_BY(mutex) = std::chrono::nanoseconds{0};
- bool scheduled GUARDED_BY(mutex) = false;
- std::optional<nsecs_t> expectedWakeupTime GUARDED_BY(mutex);
+ std::optional<nsecs_t> scheduledFrameTime GUARDED_BY(mutex);
TracedOrdinal<int> value = {"VSYNC-sf", 0};
};
@@ -127,14 +134,11 @@
Vsync mVsync;
Injector mInjector;
- sp<Handler> mHandler;
-
- void vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime);
void injectorCallback();
public:
- ~MessageQueue() override = default;
- void init(const sp<SurfaceFlinger>& flinger) override;
+ explicit MessageQueue(ICompositor&);
+
void initVsync(scheduler::VSyncDispatch&, frametimeline::TokenManager&,
std::chrono::nanoseconds workDuration) override;
void setDuration(std::chrono::nanoseconds workDuration) override;
@@ -143,13 +147,10 @@
void waitMessage() override;
void postMessage(sp<MessageHandler>&&) override;
- // sends INVALIDATE message at next VSYNC
- void invalidate() override;
+ void scheduleCommit() override;
+ void scheduleComposite() override;
- // sends REFRESH message at next VSYNC
- void refresh() override;
-
- std::optional<std::chrono::steady_clock::time_point> nextExpectedInvalidate() override;
+ std::optional<Clock::time_point> getScheduledFrameTime() const override;
};
} // namespace impl
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 12e741b..c6a19de 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -870,7 +870,7 @@
void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) {
if (timeline.refreshRequired) {
- mSchedulerCallback.scheduleRefresh(FrameHint::kNone);
+ mSchedulerCallback.scheduleComposite(FrameHint::kNone);
}
std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
@@ -882,12 +882,12 @@
}
}
-void Scheduler::onDisplayRefreshed(nsecs_t timestamp) {
- const bool refresh = [=] {
+void Scheduler::onPostComposition(nsecs_t presentTime) {
+ const bool recomposite = [=] {
std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
if (mLastVsyncPeriodChangeTimeline && mLastVsyncPeriodChangeTimeline->refreshRequired) {
- if (timestamp < mLastVsyncPeriodChangeTimeline->refreshTimeNanos) {
- // We need to schedule another refresh as refreshTimeNanos is still in the future.
+ if (presentTime < mLastVsyncPeriodChangeTimeline->refreshTimeNanos) {
+ // We need to composite again as refreshTimeNanos is still in the future.
return true;
}
@@ -896,8 +896,8 @@
return false;
}();
- if (refresh) {
- mSchedulerCallback.scheduleRefresh(FrameHint::kNone);
+ if (recomposite) {
+ mSchedulerCallback.scheduleComposite(FrameHint::kNone);
}
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 3f3debe..0a33dbb 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -59,7 +59,7 @@
// Indicates frame activity, i.e. whether commit and/or composite is taking place.
enum class FrameHint { kNone, kActive };
- virtual void scheduleRefresh(FrameHint) = 0;
+ virtual void scheduleComposite(FrameHint) = 0;
virtual void setVsyncEnabled(bool) = 0;
virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&,
scheduler::RefreshRateConfigEvent) = 0;
@@ -162,8 +162,8 @@
// Notifies the scheduler about a refresh rate timeline change.
void onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline);
- // Notifies the scheduler when the display was refreshed
- void onDisplayRefreshed(nsecs_t timestamp);
+ // Notifies the scheduler post composition.
+ void onPostComposition(nsecs_t presentTime);
// Notifies the scheduler when the display size has changed. Called from SF's main thread
void onActiveDisplayAreaChanged(uint32_t displayArea);