SF: Delegate ICompositor interfacing to Scheduler
Factor out MessageQueue's calls to commit/composite/sample into an
onFrameSignal delegate that Scheduler implements, since the policy
for ICompositor interfacing (e.g. whether to composite displays
sequentially or concurrently) will be the latter's responsibility.
Improve type correctness by replacing more nsecs_t with TimePoint/
Duration, and int64_t with a new VsyncId type.
Bug: 241285191
Test: Boot
Change-Id: I5039894038b62a562c1f93b7cea41751f7f76ca6
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index e90e387..e1ac301 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -30,7 +30,7 @@
namespace android::impl {
-void MessageQueue::Handler::dispatchFrame(int64_t vsyncId, nsecs_t expectedVsyncTime) {
+void MessageQueue::Handler::dispatchFrame(VsyncId vsyncId, TimePoint expectedVsyncTime) {
if (!mFramePending.exchange(true)) {
mVsyncId = vsyncId;
mExpectedVsyncTime = expectedVsyncTime;
@@ -44,16 +44,7 @@
void MessageQueue::Handler::handleMessage(const Message&) {
mFramePending.store(false);
-
- const nsecs_t frameTime = systemTime();
- auto& compositor = mQueue.mCompositor;
-
- if (!compositor.commit(frameTime, mVsyncId, mExpectedVsyncTime)) {
- return;
- }
-
- compositor.composite(frameTime, mVsyncId);
- compositor.sample();
+ mQueue.onFrameSignal(mQueue.mCompositor, mVsyncId, mExpectedVsyncTime);
}
MessageQueue::MessageQueue(ICompositor& compositor)
@@ -102,16 +93,17 @@
// Trace VSYNC-sf
mVsync.value = (mVsync.value + 1) % 2;
+ const auto expectedVsyncTime = TimePoint::fromNs(vsyncTime);
{
std::lock_guard lock(mVsync.mutex);
- mVsync.lastCallbackTime = std::chrono::nanoseconds(vsyncTime);
+ mVsync.lastCallbackTime = expectedVsyncTime;
mVsync.scheduledFrameTime.reset();
}
- const auto vsyncId = mVsync.tokenManager->generateTokenForPredictions(
- {targetWakeupTime, readyTime, vsyncTime});
+ const auto vsyncId = VsyncId{mVsync.tokenManager->generateTokenForPredictions(
+ {targetWakeupTime, readyTime, vsyncTime})};
- mHandler->dispatchFrame(vsyncId, vsyncTime);
+ mHandler->dispatchFrame(vsyncId, expectedVsyncTime);
}
void MessageQueue::initVsync(scheduler::VSyncDispatch& dispatch,
@@ -133,9 +125,10 @@
std::lock_guard lock(mVsync.mutex);
mVsync.workDuration = workDuration;
if (mVsync.scheduledFrameTime) {
- mVsync.scheduledFrameTime = mVsync.registration->schedule(
- {mVsync.workDuration.get().count(),
- /*readyDuration=*/0, mVsync.lastCallbackTime.count()});
+ mVsync.scheduledFrameTime =
+ mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
+ .readyDuration = 0,
+ .earliestVsync = mVsync.lastCallbackTime.ns()});
}
}
@@ -171,7 +164,7 @@
{
std::lock_guard lock(mInjector.mutex);
if (CC_UNLIKELY(mInjector.connection)) {
- ALOGD("%s while injecting VSYNC", __FUNCTION__);
+ ALOGD("%s while injecting VSYNC", __func__);
mInjector.connection->requestNextVsync();
return;
}
@@ -181,7 +174,7 @@
mVsync.scheduledFrameTime =
mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
.readyDuration = 0,
- .earliestVsync = mVsync.lastCallbackTime.count()});
+ .earliestVsync = mVsync.lastCallbackTime.ns()});
}
void MessageQueue::injectorCallback() {
@@ -190,9 +183,10 @@
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) {
- auto& vsync = buffer[i].vsync;
- mHandler->dispatchFrame(vsync.vsyncData.preferredVsyncId(),
- vsync.vsyncData.preferredExpectedPresentationTime());
+ auto& vsync = buffer[i].vsync.vsyncData;
+ mHandler->dispatchFrame(VsyncId{vsync.preferredVsyncId()},
+ TimePoint::fromNs(
+ vsync.preferredExpectedPresentationTime()));
break;
}
}
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 9dde82b..506f27b 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -28,6 +28,9 @@
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
+#include <scheduler/Time.h>
+#include <scheduler/VsyncId.h>
+
#include "EventThread.h"
#include "TracedOrdinal.h"
#include "VSyncDispatch.h"
@@ -35,8 +38,8 @@
namespace android {
struct ICompositor {
- virtual bool commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) = 0;
- virtual void composite(nsecs_t frameTime, int64_t vsyncId) = 0;
+ virtual bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) = 0;
+ virtual void composite(TimePoint frameTime, VsyncId) = 0;
virtual void sample() = 0;
protected:
@@ -88,8 +91,9 @@
class Handler : public MessageHandler {
MessageQueue& mQueue;
std::atomic_bool mFramePending = false;
- std::atomic<int64_t> mVsyncId = 0;
- std::atomic<nsecs_t> mExpectedVsyncTime = 0;
+
+ std::atomic<VsyncId> mVsyncId;
+ std::atomic<TimePoint> mExpectedVsyncTime;
public:
explicit Handler(MessageQueue& queue) : mQueue(queue) {}
@@ -97,7 +101,7 @@
bool isFramePending() const;
- virtual void dispatchFrame(int64_t vsyncId, nsecs_t expectedVsyncTime);
+ virtual void dispatchFrame(VsyncId, TimePoint expectedVsyncTime);
};
friend class Handler;
@@ -108,6 +112,8 @@
void vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime);
private:
+ virtual void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) = 0;
+
ICompositor& mCompositor;
const sp<Looper> mLooper;
const sp<Handler> mHandler;
@@ -119,7 +125,7 @@
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};
+ TimePoint lastCallbackTime GUARDED_BY(mutex);
std::optional<nsecs_t> scheduledFrameTime GUARDED_BY(mutex);
TracedOrdinal<int> value = {"VSYNC-sf", 0};
};
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index a3d4e8d..55ae013 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -131,6 +131,18 @@
}
}
+void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId,
+ TimePoint expectedVsyncTime) {
+ const TimePoint frameTime = SchedulerClock::now();
+
+ if (!compositor.commit(frameTime, vsyncId, expectedVsyncTime)) {
+ return;
+ }
+
+ compositor.composite(frameTime, vsyncId);
+ compositor.sample();
+}
+
void Scheduler::createVsyncSchedule(FeatureFlags features) {
mVsyncSchedule.emplace(features);
}
@@ -151,20 +163,20 @@
.getFrameRateOverrideForUid(uid, supportsFrameRateOverrideByContent);
}
-bool Scheduler::isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const {
+bool Scheduler::isVsyncValid(TimePoint expectedVsyncTimestamp, uid_t uid) const {
const auto frameRate = getFrameRateOverride(uid);
if (!frameRate.has_value()) {
return true;
}
- return mVsyncSchedule->getTracker().isVSyncInPhase(expectedVsyncTimestamp, *frameRate);
+ return mVsyncSchedule->getTracker().isVSyncInPhase(expectedVsyncTimestamp.ns(), *frameRate);
}
impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const {
std::scoped_lock lock(mRefreshRateConfigsLock);
return [this](nsecs_t expectedVsyncTimestamp, uid_t uid) {
- return !isVsyncValid(expectedVsyncTimestamp, uid);
+ return !isVsyncValid(TimePoint::fromNs(expectedVsyncTimestamp), uid);
};
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index f800eeb..4730493 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -192,7 +192,7 @@
// Returns true if a given vsync timestamp is considered valid vsync
// for a given uid
- bool isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const;
+ bool isVsyncValid(TimePoint expectedVsyncTimestamp, uid_t uid) const;
void dump(std::string&) const;
void dump(ConnectionHandle, std::string&) const;
@@ -243,6 +243,9 @@
enum class TimerState { Reset, Expired };
enum class TouchState { Inactive, Active };
+ // impl::MessageQueue overrides:
+ void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override;
+
// Create a connection on the given EventThread.
ConnectionHandle createConnection(std::unique_ptr<EventThread>);
sp<EventThreadConnection> createConnectionInternal(
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Time.h b/services/surfaceflinger/Scheduler/include/scheduler/Time.h
index 487709b..f00d456 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/Time.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/Time.h
@@ -46,7 +46,8 @@
struct Duration : TimePoint::duration {
// Implicit conversion from std::chrono counterpart.
- constexpr Duration(TimePoint::duration d) : TimePoint::duration(d) {}
+ template <typename R, typename P>
+ constexpr Duration(std::chrono::duration<R, P> d) : TimePoint::duration(d) {}
static constexpr Duration fromNs(nsecs_t ns) { return {std::chrono::nanoseconds(ns)}; }
@@ -65,4 +66,15 @@
return Duration(time_since_epoch()).ns();
}
+// Shorthand to convert the tick count of a Duration to Period and Rep. For example:
+//
+// const auto i = ticks<std::ratio<1>>(d); // Integer seconds.
+// const auto f = ticks<std::milli, float>(d); // Floating-point milliseconds.
+//
+template <typename Period, typename Rep = Duration::rep>
+constexpr Rep ticks(Duration d) {
+ using D = std::chrono::duration<Rep, Period>;
+ return std::chrono::duration_cast<D>(d).count();
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/VsyncId.h b/services/surfaceflinger/Scheduler/include/scheduler/VsyncId.h
new file mode 100644
index 0000000..c64a3cd
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/include/scheduler/VsyncId.h
@@ -0,0 +1,34 @@
+/*
+ * 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 <cstdint>
+
+namespace android {
+
+// TODO(b/185536303): Import StrongTyping.h into FTL so it can be used here.
+
+// Sequential frame identifier, also known as FrameTimeline token.
+struct VsyncId {
+ int64_t value = -1;
+};
+
+inline bool operator==(VsyncId lhs, VsyncId rhs) {
+ return lhs.value == rhs.value;
+}
+
+} // namespace android