summaryrefslogtreecommitdiff
path: root/services/surfaceflinger/Scheduler/MessageQueue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/surfaceflinger/Scheduler/MessageQueue.cpp')
-rw-r--r--services/surfaceflinger/Scheduler/MessageQueue.cpp149
1 files changed, 118 insertions, 31 deletions
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 6067e69ea0..4d51125156 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -14,9 +14,7 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <binder/IPCThreadState.h>
@@ -25,36 +23,42 @@
#include <utils/threads.h>
#include <gui/DisplayEventReceiver.h>
-#include <gui/IDisplayEventConnection.h>
#include "EventThread.h"
+#include "FrameTimeline.h"
#include "MessageQueue.h"
#include "SurfaceFlinger.h"
namespace android::impl {
void MessageQueue::Handler::dispatchRefresh() {
- if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) {
+ if ((mEventMask.fetch_or(eventMaskRefresh) & eventMaskRefresh) == 0) {
mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
}
}
-void MessageQueue::Handler::dispatchInvalidate(nsecs_t expectedVSyncTimestamp) {
- if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) {
+void MessageQueue::Handler::dispatchInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTimestamp) {
+ if ((mEventMask.fetch_or(eventMaskInvalidate) & eventMaskInvalidate) == 0) {
+ mVsyncId = vsyncId;
mExpectedVSyncTime = expectedVSyncTimestamp;
mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
}
}
+bool MessageQueue::Handler::invalidatePending() {
+ constexpr auto pendingMask = eventMaskInvalidate | eventMaskRefresh;
+ return (mEventMask.load() & pendingMask) != 0;
+}
+
void MessageQueue::Handler::handleMessage(const Message& message) {
switch (message.what) {
case INVALIDATE:
- android_atomic_and(~eventMaskInvalidate, &mEventMask);
- mQueue.mFlinger->onMessageReceived(message.what, mExpectedVSyncTime);
+ mEventMask.fetch_and(~eventMaskInvalidate);
+ mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime);
break;
case REFRESH:
- android_atomic_and(~eventMaskRefresh, &mEventMask);
- mQueue.mFlinger->onMessageReceived(message.what, mExpectedVSyncTime);
+ mEventMask.fetch_and(~eventMaskRefresh);
+ mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime);
break;
}
}
@@ -67,15 +71,75 @@ void MessageQueue::init(const sp<SurfaceFlinger>& flinger) {
mHandler = new Handler(*this);
}
-void MessageQueue::setEventConnection(const sp<EventThreadConnection>& connection) {
- if (mEventTube.getFd() >= 0) {
- mLooper->removeFd(mEventTube.getFd());
+// TODO(b/169865816): refactor VSyncInjections to use MessageQueue directly
+// and remove the EventThread from MessageQueue
+void MessageQueue::setInjector(sp<EventThreadConnection> connection) {
+ auto& tube = mInjector.tube;
+
+ if (const int fd = tube.getFd(); fd >= 0) {
+ mLooper->removeFd(fd);
+ }
+
+ if (connection) {
+ // The EventThreadConnection is retained when disabling injection, so avoid subsequently
+ // stealing invalid FDs. Note that the stolen FDs are kept open.
+ if (tube.getFd() < 0) {
+ connection->stealReceiveChannel(&tube);
+ } else {
+ ALOGW("Recycling channel for VSYNC injection.");
+ }
+
+ mLooper->addFd(
+ tube.getFd(), 0, Looper::EVENT_INPUT,
+ [](int, int, void* data) {
+ reinterpret_cast<MessageQueue*>(data)->injectorCallback();
+ return 1; // Keep registration.
+ },
+ this);
+ }
+
+ std::lock_guard lock(mInjector.mutex);
+ mInjector.connection = std::move(connection);
+}
+
+void MessageQueue::vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime) {
+ ATRACE_CALL();
+ // Trace VSYNC-sf
+ mVsync.value = (mVsync.value + 1) % 2;
+
+ {
+ std::lock_guard lock(mVsync.mutex);
+ mVsync.lastCallbackTime = std::chrono::nanoseconds(vsyncTime);
+ mVsync.scheduled = false;
}
+ mHandler->dispatchInvalidate(mVsync.tokenManager->generateTokenForPredictions(
+ {targetWakeupTime, readyTime, vsyncTime}),
+ vsyncTime);
+}
+
+void MessageQueue::initVsync(scheduler::VSyncDispatch& dispatch,
+ frametimeline::TokenManager& tokenManager,
+ std::chrono::nanoseconds workDuration) {
+ setDuration(workDuration);
+ mVsync.tokenManager = &tokenManager;
+ mVsync.registration = std::make_unique<
+ scheduler::VSyncCallbackRegistration>(dispatch,
+ std::bind(&MessageQueue::vsyncCallback, this,
+ std::placeholders::_1,
+ std::placeholders::_2,
+ std::placeholders::_3),
+ "sf");
+}
- mEvents = connection;
- mEvents->stealReceiveChannel(&mEventTube);
- mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
- this);
+void MessageQueue::setDuration(std::chrono::nanoseconds workDuration) {
+ ATRACE_CALL();
+ std::lock_guard lock(mVsync.mutex);
+ mVsync.workDuration = workDuration;
+ if (mVsync.scheduled) {
+ mVsync.expectedWakeupTime = mVsync.registration->schedule(
+ {mVsync.workDuration.get().count(),
+ /*readyDuration=*/0, mVsync.lastCallbackTime.count()});
+ }
}
void MessageQueue::waitMessage() {
@@ -105,33 +169,56 @@ void MessageQueue::postMessage(sp<MessageHandler>&& handler) {
}
void MessageQueue::invalidate() {
- mEvents->requestNextVsync();
+ ATRACE_CALL();
+
+ {
+ std::lock_guard lock(mInjector.mutex);
+ if (CC_UNLIKELY(mInjector.connection)) {
+ ALOGD("%s while injecting VSYNC", __FUNCTION__);
+ mInjector.connection->requestNextVsync();
+ return;
+ }
+ }
+
+ std::lock_guard lock(mVsync.mutex);
+ mVsync.scheduled = true;
+ mVsync.expectedWakeupTime =
+ mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
+ .readyDuration = 0,
+ .earliestVsync = mVsync.lastCallbackTime.count()});
}
void MessageQueue::refresh() {
mHandler->dispatchRefresh();
}
-int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
- MessageQueue* queue = reinterpret_cast<MessageQueue*>(data);
- return queue->eventReceiver(fd, events);
-}
-
-int MessageQueue::eventReceiver(int /*fd*/, int /*events*/) {
+void MessageQueue::injectorCallback() {
ssize_t n;
DisplayEventReceiver::Event buffer[8];
- while ((n = DisplayEventReceiver::getEvents(&mEventTube, buffer, 8)) > 0) {
+ 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.expectedVSyncTimestamp);
+ mHandler->dispatchInvalidate(buffer[i].vsync.vsyncId,
+ buffer[i].vsync.expectedVSyncTimestamp);
break;
}
}
}
- return 1;
}
-} // namespace android::impl
+std::optional<std::chrono::steady_clock::time_point> MessageQueue::nextExpectedInvalidate() {
+ if (mHandler->invalidatePending()) {
+ return std::chrono::steady_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);
+ }
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+ return std::nullopt;
+}
+
+} // namespace android::impl