From 57674f3ad14d6ac05aef09acffd2256e0a65308a Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Thu, 23 Sep 2021 13:27:53 -0700 Subject: Plumb expected present time to Choreographer. Bug: 198191648 Test: make Change-Id: I46ed20676ffddccc83aec11801adc4c875ac6f00 --- libs/gui/DisplayEventDispatcher.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'libs/gui/DisplayEventDispatcher.cpp') diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index e1b1efc0ed..6f1a7aed9c 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -153,6 +153,7 @@ bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, outVsyncEventData->id = ev.vsync.vsyncId; outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp; outVsyncEventData->frameInterval = ev.vsync.frameInterval; + outVsyncEventData->expectedPresentTime = ev.vsync.expectedVSyncTimestamp; break; case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected); -- cgit v1.2.3-59-g8ed1b From 6b1807002ebd198f51cdb70c3fee79645bd25fe8 Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Wed, 6 Oct 2021 19:13:50 -0700 Subject: Send multiple scheduler frame timelines. Fixed array amount for FrameTimelines. Bug: 198192508 Test: atest ChoreographerNativeTest Change-Id: If0e9304fa114b700b861be6d51a4253f097514c3 --- libs/gui/DisplayEventDispatcher.cpp | 16 +++++++ libs/gui/include/gui/DisplayEventDispatcher.h | 24 ++++++++++ libs/gui/include/gui/DisplayEventReceiver.h | 9 ++++ libs/nativedisplay/AChoreographer.cpp | 34 +++++---------- services/surfaceflinger/Scheduler/EventThread.cpp | 45 +++++++++++++++---- services/surfaceflinger/Scheduler/EventThread.h | 4 ++ .../tests/unittests/EventThreadTest.cpp | 51 +++++++++++++++++++++- 7 files changed, 150 insertions(+), 33 deletions(-) (limited to 'libs/gui/DisplayEventDispatcher.cpp') diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index 6f1a7aed9c..c986b82fd8 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -130,6 +130,19 @@ int DisplayEventDispatcher::handleEvent(int, int events, void*) { return 1; // keep the callback } +void DisplayEventDispatcher::populateFrameTimelines(const DisplayEventReceiver::Event& event, + VsyncEventData* outVsyncEventData) const { + for (size_t i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) { + DisplayEventReceiver::Event::VSync::FrameTimeline receiverTimeline = + event.vsync.frameTimelines[i]; + outVsyncEventData->frameTimelines[i] = {.id = receiverTimeline.vsyncId, + .deadlineTimestamp = + receiverTimeline.deadlineTimestamp, + .expectedPresentTime = + receiverTimeline.expectedVSyncTimestamp}; + } +} + bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, uint32_t* outCount, @@ -154,6 +167,9 @@ bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp; outVsyncEventData->frameInterval = ev.vsync.frameInterval; outVsyncEventData->expectedPresentTime = ev.vsync.expectedVSyncTimestamp; + outVsyncEventData->preferredFrameTimelineIndex = + ev.vsync.preferredFrameTimelineIndex; + populateFrameTimelines(ev, outVsyncEventData); break; case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected); diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index f3bd139e8c..92c89b8bde 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -17,6 +17,7 @@ #include #include #include +#include namespace android { using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; @@ -36,6 +37,26 @@ struct VsyncEventData { // The anticipated Vsync present time. int64_t expectedPresentTime = 0; + + struct FrameTimeline { + // The Vsync Id corresponsing to this vsync event. This will be used to + // populate ISurfaceComposer::setFrameTimelineVsync and + // SurfaceComposerClient::setFrameTimelineVsync + int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID; + + // The deadline in CLOCK_MONOTONIC that the app needs to complete its + // frame by (both on the CPU and the GPU) + int64_t deadlineTimestamp = std::numeric_limits::max(); + + // The anticipated Vsync present time. + int64_t expectedPresentTime = 0; + }; + + // Sorted possible frame timelines. + std::array frameTimelines; + + // Index into the frameTimelines that represents the platform's preferred frame timeline. + size_t preferredFrameTimelineIndex = std::numeric_limits::max(); }; class DisplayEventDispatcher : public LooperCallback { @@ -77,5 +98,8 @@ private: bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, uint32_t* outCount, VsyncEventData* outVsyncEventData); + + void populateFrameTimelines(const DisplayEventReceiver::Event& event, + VsyncEventData* outVsyncEventData) const; }; } // namespace android diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index 0dffbde88a..ca368433b1 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -49,6 +49,9 @@ static inline constexpr uint32_t fourcc(char c1, char c2, char c3, char c4) { // ---------------------------------------------------------------------------- class DisplayEventReceiver { public: + // Max amount of frame timelines is arbitrarily set to be reasonable. + static constexpr int64_t kFrameTimelinesLength = 7; + enum { DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'), DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'), @@ -77,6 +80,12 @@ public: nsecs_t deadlineTimestamp __attribute__((aligned(8))); nsecs_t frameInterval __attribute__((aligned(8))); int64_t vsyncId; + size_t preferredFrameTimelineIndex __attribute__((aligned(8))); + struct FrameTimeline { + nsecs_t expectedVSyncTimestamp __attribute__((aligned(8))); + nsecs_t deadlineTimestamp __attribute__((aligned(8))); + int64_t vsyncId; + } frameTimelines[kFrameTimelinesLength]; }; struct Hotplug { diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index 79d9b9313c..fc9680babb 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -100,17 +100,10 @@ class Choreographer; * Implementation of AChoreographerFrameCallbackData. */ struct ChoreographerFrameCallbackDataImpl { - struct FrameTimeline { - int64_t vsyncId{0}; - int64_t expectedPresentTimeNanos{0}; - int64_t deadlineNanos{0}; - }; - int64_t frameTimeNanos{0}; - size_t frameTimelinesLength; - - std::vector frameTimelines; + std::array + frameTimelines; size_t preferredFrameTimelineIndex; @@ -456,14 +449,9 @@ bool Choreographer::inCallback() const { } ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const { - std::vector frameTimelines; - frameTimelines.push_back({.vsyncId = mLastVsyncEventData.id, - .expectedPresentTimeNanos = mLastVsyncEventData.expectedPresentTime, - .deadlineNanos = mLastVsyncEventData.deadlineTimestamp}); return {.frameTimeNanos = timestamp, - .frameTimelinesLength = 1, - .preferredFrameTimelineIndex = 0, - .frameTimelines = frameTimelines, + .preferredFrameTimelineIndex = mLastVsyncEventData.preferredFrameTimelineIndex, + .frameTimelines = mLastVsyncEventData.frameTimelines, .choreographer = this}; } @@ -646,7 +634,7 @@ size_t AChoreographerFrameCallbackData_getFrameTimelinesLength( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - return frameCallbackData->frameTimelinesLength; + return frameCallbackData->frameTimelines.size(); } size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex( const AChoreographerFrameCallbackData* data) { @@ -662,8 +650,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineVsyncId( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); - return frameCallbackData->frameTimelines[index].vsyncId; + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); + return frameCallbackData->frameTimelines[index].id; } int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime( const AChoreographerFrameCallbackData* data, size_t index) { @@ -671,8 +659,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); - return frameCallbackData->frameTimelines[index].expectedPresentTimeNanos; + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); + return frameCallbackData->frameTimelines[index].expectedPresentTime; } int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline( const AChoreographerFrameCallbackData* data, size_t index) { @@ -680,8 +668,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); - return frameCallbackData->frameTimelines[index].deadlineNanos; + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); + return frameCallbackData->frameTimelines[index].deadlineTimestamp; } AChoreographer* AChoreographer_create() { diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 2bdcaf6ad0..e07eae79c8 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -355,14 +355,7 @@ void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp std::lock_guard lock(mMutex); LOG_FATAL_IF(!mVSyncState); - const int64_t vsyncId = [&] { - if (mTokenManager != nullptr) { - return mTokenManager->generateTokenForPredictions( - {timestamp, deadlineTimestamp, expectedVSyncTimestamp}); - } - return FrameTimelineInfo::INVALID_VSYNC_ID; - }(); - + const int64_t vsyncId = generateToken(timestamp, deadlineTimestamp, expectedVSyncTimestamp); mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count, expectedVSyncTimestamp, deadlineTimestamp, vsyncId)); mCondition.notify_all(); @@ -567,12 +560,48 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, } } +int64_t EventThread::generateToken(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, + nsecs_t deadlineTimestamp) const { + if (mTokenManager != nullptr) { + return mTokenManager->generateTokenForPredictions( + {timestamp, deadlineTimestamp, expectedVSyncTimestamp}); + } + return FrameTimelineInfo::INVALID_VSYNC_ID; +} + +void EventThread::generateFrameTimeline(DisplayEventReceiver::Event& event) const { + // Add 1 to ensure the preferredFrameTimelineIndex entry (when multiplier == 0) is included. + for (int multiplier = -DisplayEventReceiver::kFrameTimelinesLength + 1, currentIndex = 0; + currentIndex < DisplayEventReceiver::kFrameTimelinesLength; multiplier++) { + nsecs_t deadline = event.vsync.deadlineTimestamp + multiplier * event.vsync.frameInterval; + // Valid possible frame timelines must have future values. + if (deadline > event.header.timestamp) { + if (multiplier == 0) { + event.vsync.preferredFrameTimelineIndex = currentIndex; + event.vsync.frameTimelines[currentIndex] = + {.vsyncId = event.vsync.vsyncId, + .deadlineTimestamp = event.vsync.deadlineTimestamp, + .expectedVSyncTimestamp = event.vsync.expectedVSyncTimestamp}; + } else { + nsecs_t expectedVSync = + event.vsync.expectedVSyncTimestamp + multiplier * event.vsync.frameInterval; + event.vsync.frameTimelines[currentIndex] = + {.vsyncId = generateToken(event.header.timestamp, expectedVSync, deadline), + .deadlineTimestamp = deadline, + .expectedVSyncTimestamp = expectedVSync}; + } + currentIndex++; + } + } +} + void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, const DisplayEventConsumers& consumers) { for (const auto& consumer : consumers) { DisplayEventReceiver::Event copy = event; if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { copy.vsync.frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid); + generateFrameTimeline(copy); } switch (consumer->postEvent(copy)) { case NO_ERROR: diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 9265a25b86..73ae5dc9e3 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -204,6 +204,10 @@ private: void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, nsecs_t deadlineTimestamp) override; + int64_t generateToken(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, + nsecs_t deadlineTimestamp) const; + void generateFrameTimeline(DisplayEventReceiver::Event& event) const; + const std::unique_ptr mVSyncSource GUARDED_BY(mMutex); frametimeline::TokenManager* const mTokenManager; diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 28d0222829..cb690aa0e4 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -28,6 +28,7 @@ #include "AsyncCallRecorder.h" #include "DisplayHardware/DisplayMode.h" +#include "FrameTimeline.h" #include "Scheduler/EventThread.h" using namespace std::chrono_literals; @@ -96,6 +97,8 @@ protected: ConnectionEventRecorder& connectionEventRecorder, nsecs_t expectedTimestamp, unsigned expectedCount); void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount); + void expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp, + nsecs_t preferredDeadline); void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, bool expectedConnected); void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, @@ -120,6 +123,7 @@ protected: std::unique_ptr mThread; sp mConnection; sp mThrottledConnection; + std::unique_ptr mTokenManager; static constexpr uid_t mConnectionUid = 443; static constexpr uid_t mThrottledConnectionUid = 177; @@ -173,8 +177,8 @@ void EventThreadTest::createThread(std::unique_ptr source) { return VSYNC_PERIOD.count(); }; - mThread = std::make_unique(std::move(source), - /*tokenManager=*/nullptr, + mTokenManager = std::make_unique(); + mThread = std::make_unique(std::move(source), mTokenManager.get(), mInterceptVSyncCallRecorder.getInvocable(), throttleVsync, getVsyncPeriod); @@ -247,6 +251,36 @@ void EventThreadTest::expectVsyncEventReceivedByConnection(nsecs_t expectedTimes expectedCount); } +void EventThreadTest::expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp, + nsecs_t preferredDeadline) { + auto args = mConnectionEventCallRecorder.waitForCall(); + ASSERT_TRUE(args.has_value()) << " did not receive an event for timestamp " + << expectedTimestamp; + const auto& event = std::get<0>(args.value()); + for (int i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) { + if (i > 0) { + EXPECT_GT(event.vsync.frameTimelines[i].deadlineTimestamp, + event.vsync.frameTimelines[i - 1].deadlineTimestamp) + << "Deadline timestamp out of order for frame timeline " << i; + EXPECT_GT(event.vsync.frameTimelines[i].expectedVSyncTimestamp, + event.vsync.frameTimelines[i - 1].expectedVSyncTimestamp) + << "Expected vsync timestamp out of order for frame timeline " << i; + } + if (event.vsync.frameTimelines[i].deadlineTimestamp == preferredDeadline) { + EXPECT_EQ(i, event.vsync.preferredFrameTimelineIndex) + << "Preferred frame timeline index should be " << i; + // For the platform-preferred frame timeline, the vsync ID is 0 because the first frame + // timeline is made before the rest. + EXPECT_EQ(0, event.vsync.frameTimelines[i].vsyncId) + << "Vsync ID incorrect for frame timeline " << i; + } else { + // Vsync ID 0 is used for the preferred frame timeline. + EXPECT_EQ(i + 1, event.vsync.frameTimelines[i].vsyncId) + << "Vsync ID incorrect for frame timeline " << i; + } + } +} + void EventThreadTest::expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, bool expectedConnected) { auto args = mConnectionEventCallRecorder.waitForCall(); @@ -344,6 +378,19 @@ TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) { expectVSyncSetEnabledCallReceived(false); } +TEST_F(EventThreadTest, requestNextVsyncEventFrameTimelinesCorrect) { + // Signal that we want the next vsync event to be posted to the connection + mThread->requestNextVsync(mConnection); + + expectVSyncSetEnabledCallReceived(true); + + // Use the received callback to signal a vsync event. + // The interceptor should receive the event, as well as the connection. + mCallback->onVSyncEvent(123, 456, 789); + expectInterceptCallReceived(123); + expectVsyncEventFrameTimelinesCorrect(123, 789); +} + TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) { // Create a first connection, register it, and request a vsync rate of zero. ConnectionEventRecorder firstConnectionEventRecorder{0}; -- cgit v1.2.3-59-g8ed1b From caaa47d60b83670206dcd3c34382719b1f247ab5 Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Fri, 29 Oct 2021 18:03:52 +0000 Subject: Revert "Send multiple scheduler frame timelines." This reverts commit 6b1807002ebd198f51cdb70c3fee79645bd25fe8. Reason for revert: b/204492891 Change-Id: I292c11a0c54c57d97d112d9cec16b27acaa7b6a6 --- libs/gui/DisplayEventDispatcher.cpp | 16 ------- libs/gui/include/gui/DisplayEventDispatcher.h | 24 ---------- libs/gui/include/gui/DisplayEventReceiver.h | 9 ---- libs/nativedisplay/AChoreographer.cpp | 34 ++++++++++----- services/surfaceflinger/Scheduler/EventThread.cpp | 45 ++++--------------- services/surfaceflinger/Scheduler/EventThread.h | 4 -- .../tests/unittests/EventThreadTest.cpp | 51 +--------------------- 7 files changed, 33 insertions(+), 150 deletions(-) (limited to 'libs/gui/DisplayEventDispatcher.cpp') diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index c986b82fd8..6f1a7aed9c 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -130,19 +130,6 @@ int DisplayEventDispatcher::handleEvent(int, int events, void*) { return 1; // keep the callback } -void DisplayEventDispatcher::populateFrameTimelines(const DisplayEventReceiver::Event& event, - VsyncEventData* outVsyncEventData) const { - for (size_t i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) { - DisplayEventReceiver::Event::VSync::FrameTimeline receiverTimeline = - event.vsync.frameTimelines[i]; - outVsyncEventData->frameTimelines[i] = {.id = receiverTimeline.vsyncId, - .deadlineTimestamp = - receiverTimeline.deadlineTimestamp, - .expectedPresentTime = - receiverTimeline.expectedVSyncTimestamp}; - } -} - bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, uint32_t* outCount, @@ -167,9 +154,6 @@ bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp; outVsyncEventData->frameInterval = ev.vsync.frameInterval; outVsyncEventData->expectedPresentTime = ev.vsync.expectedVSyncTimestamp; - outVsyncEventData->preferredFrameTimelineIndex = - ev.vsync.preferredFrameTimelineIndex; - populateFrameTimelines(ev, outVsyncEventData); break; case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected); diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index 92c89b8bde..f3bd139e8c 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -17,7 +17,6 @@ #include #include #include -#include namespace android { using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; @@ -37,26 +36,6 @@ struct VsyncEventData { // The anticipated Vsync present time. int64_t expectedPresentTime = 0; - - struct FrameTimeline { - // The Vsync Id corresponsing to this vsync event. This will be used to - // populate ISurfaceComposer::setFrameTimelineVsync and - // SurfaceComposerClient::setFrameTimelineVsync - int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID; - - // The deadline in CLOCK_MONOTONIC that the app needs to complete its - // frame by (both on the CPU and the GPU) - int64_t deadlineTimestamp = std::numeric_limits::max(); - - // The anticipated Vsync present time. - int64_t expectedPresentTime = 0; - }; - - // Sorted possible frame timelines. - std::array frameTimelines; - - // Index into the frameTimelines that represents the platform's preferred frame timeline. - size_t preferredFrameTimelineIndex = std::numeric_limits::max(); }; class DisplayEventDispatcher : public LooperCallback { @@ -98,8 +77,5 @@ private: bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, uint32_t* outCount, VsyncEventData* outVsyncEventData); - - void populateFrameTimelines(const DisplayEventReceiver::Event& event, - VsyncEventData* outVsyncEventData) const; }; } // namespace android diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index ca368433b1..0dffbde88a 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -49,9 +49,6 @@ static inline constexpr uint32_t fourcc(char c1, char c2, char c3, char c4) { // ---------------------------------------------------------------------------- class DisplayEventReceiver { public: - // Max amount of frame timelines is arbitrarily set to be reasonable. - static constexpr int64_t kFrameTimelinesLength = 7; - enum { DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'), DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'), @@ -80,12 +77,6 @@ public: nsecs_t deadlineTimestamp __attribute__((aligned(8))); nsecs_t frameInterval __attribute__((aligned(8))); int64_t vsyncId; - size_t preferredFrameTimelineIndex __attribute__((aligned(8))); - struct FrameTimeline { - nsecs_t expectedVSyncTimestamp __attribute__((aligned(8))); - nsecs_t deadlineTimestamp __attribute__((aligned(8))); - int64_t vsyncId; - } frameTimelines[kFrameTimelinesLength]; }; struct Hotplug { diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index fc9680babb..79d9b9313c 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -100,10 +100,17 @@ class Choreographer; * Implementation of AChoreographerFrameCallbackData. */ struct ChoreographerFrameCallbackDataImpl { + struct FrameTimeline { + int64_t vsyncId{0}; + int64_t expectedPresentTimeNanos{0}; + int64_t deadlineNanos{0}; + }; + int64_t frameTimeNanos{0}; - std::array - frameTimelines; + size_t frameTimelinesLength; + + std::vector frameTimelines; size_t preferredFrameTimelineIndex; @@ -449,9 +456,14 @@ bool Choreographer::inCallback() const { } ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const { + std::vector frameTimelines; + frameTimelines.push_back({.vsyncId = mLastVsyncEventData.id, + .expectedPresentTimeNanos = mLastVsyncEventData.expectedPresentTime, + .deadlineNanos = mLastVsyncEventData.deadlineTimestamp}); return {.frameTimeNanos = timestamp, - .preferredFrameTimelineIndex = mLastVsyncEventData.preferredFrameTimelineIndex, - .frameTimelines = mLastVsyncEventData.frameTimelines, + .frameTimelinesLength = 1, + .preferredFrameTimelineIndex = 0, + .frameTimelines = frameTimelines, .choreographer = this}; } @@ -634,7 +646,7 @@ size_t AChoreographerFrameCallbackData_getFrameTimelinesLength( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - return frameCallbackData->frameTimelines.size(); + return frameCallbackData->frameTimelinesLength; } size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex( const AChoreographerFrameCallbackData* data) { @@ -650,8 +662,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineVsyncId( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); - return frameCallbackData->frameTimelines[index].id; + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); + return frameCallbackData->frameTimelines[index].vsyncId; } int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime( const AChoreographerFrameCallbackData* data, size_t index) { @@ -659,8 +671,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); - return frameCallbackData->frameTimelines[index].expectedPresentTime; + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); + return frameCallbackData->frameTimelines[index].expectedPresentTimeNanos; } int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline( const AChoreographerFrameCallbackData* data, size_t index) { @@ -668,8 +680,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); - return frameCallbackData->frameTimelines[index].deadlineTimestamp; + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); + return frameCallbackData->frameTimelines[index].deadlineNanos; } AChoreographer* AChoreographer_create() { diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index e07eae79c8..2bdcaf6ad0 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -355,7 +355,14 @@ void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp std::lock_guard lock(mMutex); LOG_FATAL_IF(!mVSyncState); - const int64_t vsyncId = generateToken(timestamp, deadlineTimestamp, expectedVSyncTimestamp); + const int64_t vsyncId = [&] { + if (mTokenManager != nullptr) { + return mTokenManager->generateTokenForPredictions( + {timestamp, deadlineTimestamp, expectedVSyncTimestamp}); + } + return FrameTimelineInfo::INVALID_VSYNC_ID; + }(); + mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count, expectedVSyncTimestamp, deadlineTimestamp, vsyncId)); mCondition.notify_all(); @@ -560,48 +567,12 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, } } -int64_t EventThread::generateToken(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, - nsecs_t deadlineTimestamp) const { - if (mTokenManager != nullptr) { - return mTokenManager->generateTokenForPredictions( - {timestamp, deadlineTimestamp, expectedVSyncTimestamp}); - } - return FrameTimelineInfo::INVALID_VSYNC_ID; -} - -void EventThread::generateFrameTimeline(DisplayEventReceiver::Event& event) const { - // Add 1 to ensure the preferredFrameTimelineIndex entry (when multiplier == 0) is included. - for (int multiplier = -DisplayEventReceiver::kFrameTimelinesLength + 1, currentIndex = 0; - currentIndex < DisplayEventReceiver::kFrameTimelinesLength; multiplier++) { - nsecs_t deadline = event.vsync.deadlineTimestamp + multiplier * event.vsync.frameInterval; - // Valid possible frame timelines must have future values. - if (deadline > event.header.timestamp) { - if (multiplier == 0) { - event.vsync.preferredFrameTimelineIndex = currentIndex; - event.vsync.frameTimelines[currentIndex] = - {.vsyncId = event.vsync.vsyncId, - .deadlineTimestamp = event.vsync.deadlineTimestamp, - .expectedVSyncTimestamp = event.vsync.expectedVSyncTimestamp}; - } else { - nsecs_t expectedVSync = - event.vsync.expectedVSyncTimestamp + multiplier * event.vsync.frameInterval; - event.vsync.frameTimelines[currentIndex] = - {.vsyncId = generateToken(event.header.timestamp, expectedVSync, deadline), - .deadlineTimestamp = deadline, - .expectedVSyncTimestamp = expectedVSync}; - } - currentIndex++; - } - } -} - void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, const DisplayEventConsumers& consumers) { for (const auto& consumer : consumers) { DisplayEventReceiver::Event copy = event; if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { copy.vsync.frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid); - generateFrameTimeline(copy); } switch (consumer->postEvent(copy)) { case NO_ERROR: diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 73ae5dc9e3..9265a25b86 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -204,10 +204,6 @@ private: void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, nsecs_t deadlineTimestamp) override; - int64_t generateToken(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, - nsecs_t deadlineTimestamp) const; - void generateFrameTimeline(DisplayEventReceiver::Event& event) const; - const std::unique_ptr mVSyncSource GUARDED_BY(mMutex); frametimeline::TokenManager* const mTokenManager; diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index cb690aa0e4..28d0222829 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -28,7 +28,6 @@ #include "AsyncCallRecorder.h" #include "DisplayHardware/DisplayMode.h" -#include "FrameTimeline.h" #include "Scheduler/EventThread.h" using namespace std::chrono_literals; @@ -97,8 +96,6 @@ protected: ConnectionEventRecorder& connectionEventRecorder, nsecs_t expectedTimestamp, unsigned expectedCount); void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount); - void expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp, - nsecs_t preferredDeadline); void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, bool expectedConnected); void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, @@ -123,7 +120,6 @@ protected: std::unique_ptr mThread; sp mConnection; sp mThrottledConnection; - std::unique_ptr mTokenManager; static constexpr uid_t mConnectionUid = 443; static constexpr uid_t mThrottledConnectionUid = 177; @@ -177,8 +173,8 @@ void EventThreadTest::createThread(std::unique_ptr source) { return VSYNC_PERIOD.count(); }; - mTokenManager = std::make_unique(); - mThread = std::make_unique(std::move(source), mTokenManager.get(), + mThread = std::make_unique(std::move(source), + /*tokenManager=*/nullptr, mInterceptVSyncCallRecorder.getInvocable(), throttleVsync, getVsyncPeriod); @@ -251,36 +247,6 @@ void EventThreadTest::expectVsyncEventReceivedByConnection(nsecs_t expectedTimes expectedCount); } -void EventThreadTest::expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp, - nsecs_t preferredDeadline) { - auto args = mConnectionEventCallRecorder.waitForCall(); - ASSERT_TRUE(args.has_value()) << " did not receive an event for timestamp " - << expectedTimestamp; - const auto& event = std::get<0>(args.value()); - for (int i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) { - if (i > 0) { - EXPECT_GT(event.vsync.frameTimelines[i].deadlineTimestamp, - event.vsync.frameTimelines[i - 1].deadlineTimestamp) - << "Deadline timestamp out of order for frame timeline " << i; - EXPECT_GT(event.vsync.frameTimelines[i].expectedVSyncTimestamp, - event.vsync.frameTimelines[i - 1].expectedVSyncTimestamp) - << "Expected vsync timestamp out of order for frame timeline " << i; - } - if (event.vsync.frameTimelines[i].deadlineTimestamp == preferredDeadline) { - EXPECT_EQ(i, event.vsync.preferredFrameTimelineIndex) - << "Preferred frame timeline index should be " << i; - // For the platform-preferred frame timeline, the vsync ID is 0 because the first frame - // timeline is made before the rest. - EXPECT_EQ(0, event.vsync.frameTimelines[i].vsyncId) - << "Vsync ID incorrect for frame timeline " << i; - } else { - // Vsync ID 0 is used for the preferred frame timeline. - EXPECT_EQ(i + 1, event.vsync.frameTimelines[i].vsyncId) - << "Vsync ID incorrect for frame timeline " << i; - } - } -} - void EventThreadTest::expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, bool expectedConnected) { auto args = mConnectionEventCallRecorder.waitForCall(); @@ -378,19 +344,6 @@ TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) { expectVSyncSetEnabledCallReceived(false); } -TEST_F(EventThreadTest, requestNextVsyncEventFrameTimelinesCorrect) { - // Signal that we want the next vsync event to be posted to the connection - mThread->requestNextVsync(mConnection); - - expectVSyncSetEnabledCallReceived(true); - - // Use the received callback to signal a vsync event. - // The interceptor should receive the event, as well as the connection. - mCallback->onVSyncEvent(123, 456, 789); - expectInterceptCallReceived(123); - expectVsyncEventFrameTimelinesCorrect(123, 789); -} - TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) { // Create a first connection, register it, and request a vsync rate of zero. ConnectionEventRecorder firstConnectionEventRecorder{0}; -- cgit v1.2.3-59-g8ed1b From 3f0286607e9d35196fdff27f84381dffb7bafcad Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Thu, 4 Nov 2021 19:32:24 +0000 Subject: Revert "Revert "Send multiple scheduler frame timelines."" This reverts commit caaa47d60b83670206dcd3c34382719b1f247ab5. Reason for revert: Fix the reverted CL in 2nd CL. Bug: 198192508 Bug: 204941507 Test: See 2nd CL. Change-Id: I15c693c2e0a82ef81a490319da11871bd74298b3 --- libs/gui/DisplayEventDispatcher.cpp | 16 +++++++ libs/gui/include/gui/DisplayEventDispatcher.h | 24 ++++++++++ libs/gui/include/gui/DisplayEventReceiver.h | 9 ++++ libs/nativedisplay/AChoreographer.cpp | 34 +++++---------- services/surfaceflinger/Scheduler/EventThread.cpp | 45 +++++++++++++++---- services/surfaceflinger/Scheduler/EventThread.h | 4 ++ .../tests/unittests/EventThreadTest.cpp | 51 +++++++++++++++++++++- 7 files changed, 150 insertions(+), 33 deletions(-) (limited to 'libs/gui/DisplayEventDispatcher.cpp') diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index 6f1a7aed9c..c986b82fd8 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -130,6 +130,19 @@ int DisplayEventDispatcher::handleEvent(int, int events, void*) { return 1; // keep the callback } +void DisplayEventDispatcher::populateFrameTimelines(const DisplayEventReceiver::Event& event, + VsyncEventData* outVsyncEventData) const { + for (size_t i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) { + DisplayEventReceiver::Event::VSync::FrameTimeline receiverTimeline = + event.vsync.frameTimelines[i]; + outVsyncEventData->frameTimelines[i] = {.id = receiverTimeline.vsyncId, + .deadlineTimestamp = + receiverTimeline.deadlineTimestamp, + .expectedPresentTime = + receiverTimeline.expectedVSyncTimestamp}; + } +} + bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, uint32_t* outCount, @@ -154,6 +167,9 @@ bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp; outVsyncEventData->frameInterval = ev.vsync.frameInterval; outVsyncEventData->expectedPresentTime = ev.vsync.expectedVSyncTimestamp; + outVsyncEventData->preferredFrameTimelineIndex = + ev.vsync.preferredFrameTimelineIndex; + populateFrameTimelines(ev, outVsyncEventData); break; case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected); diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index f3bd139e8c..92c89b8bde 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -17,6 +17,7 @@ #include #include #include +#include namespace android { using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; @@ -36,6 +37,26 @@ struct VsyncEventData { // The anticipated Vsync present time. int64_t expectedPresentTime = 0; + + struct FrameTimeline { + // The Vsync Id corresponsing to this vsync event. This will be used to + // populate ISurfaceComposer::setFrameTimelineVsync and + // SurfaceComposerClient::setFrameTimelineVsync + int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID; + + // The deadline in CLOCK_MONOTONIC that the app needs to complete its + // frame by (both on the CPU and the GPU) + int64_t deadlineTimestamp = std::numeric_limits::max(); + + // The anticipated Vsync present time. + int64_t expectedPresentTime = 0; + }; + + // Sorted possible frame timelines. + std::array frameTimelines; + + // Index into the frameTimelines that represents the platform's preferred frame timeline. + size_t preferredFrameTimelineIndex = std::numeric_limits::max(); }; class DisplayEventDispatcher : public LooperCallback { @@ -77,5 +98,8 @@ private: bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, uint32_t* outCount, VsyncEventData* outVsyncEventData); + + void populateFrameTimelines(const DisplayEventReceiver::Event& event, + VsyncEventData* outVsyncEventData) const; }; } // namespace android diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index 0dffbde88a..ca368433b1 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -49,6 +49,9 @@ static inline constexpr uint32_t fourcc(char c1, char c2, char c3, char c4) { // ---------------------------------------------------------------------------- class DisplayEventReceiver { public: + // Max amount of frame timelines is arbitrarily set to be reasonable. + static constexpr int64_t kFrameTimelinesLength = 7; + enum { DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'), DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'), @@ -77,6 +80,12 @@ public: nsecs_t deadlineTimestamp __attribute__((aligned(8))); nsecs_t frameInterval __attribute__((aligned(8))); int64_t vsyncId; + size_t preferredFrameTimelineIndex __attribute__((aligned(8))); + struct FrameTimeline { + nsecs_t expectedVSyncTimestamp __attribute__((aligned(8))); + nsecs_t deadlineTimestamp __attribute__((aligned(8))); + int64_t vsyncId; + } frameTimelines[kFrameTimelinesLength]; }; struct Hotplug { diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index 79d9b9313c..fc9680babb 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -100,17 +100,10 @@ class Choreographer; * Implementation of AChoreographerFrameCallbackData. */ struct ChoreographerFrameCallbackDataImpl { - struct FrameTimeline { - int64_t vsyncId{0}; - int64_t expectedPresentTimeNanos{0}; - int64_t deadlineNanos{0}; - }; - int64_t frameTimeNanos{0}; - size_t frameTimelinesLength; - - std::vector frameTimelines; + std::array + frameTimelines; size_t preferredFrameTimelineIndex; @@ -456,14 +449,9 @@ bool Choreographer::inCallback() const { } ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const { - std::vector frameTimelines; - frameTimelines.push_back({.vsyncId = mLastVsyncEventData.id, - .expectedPresentTimeNanos = mLastVsyncEventData.expectedPresentTime, - .deadlineNanos = mLastVsyncEventData.deadlineTimestamp}); return {.frameTimeNanos = timestamp, - .frameTimelinesLength = 1, - .preferredFrameTimelineIndex = 0, - .frameTimelines = frameTimelines, + .preferredFrameTimelineIndex = mLastVsyncEventData.preferredFrameTimelineIndex, + .frameTimelines = mLastVsyncEventData.frameTimelines, .choreographer = this}; } @@ -646,7 +634,7 @@ size_t AChoreographerFrameCallbackData_getFrameTimelinesLength( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - return frameCallbackData->frameTimelinesLength; + return frameCallbackData->frameTimelines.size(); } size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex( const AChoreographerFrameCallbackData* data) { @@ -662,8 +650,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineVsyncId( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); - return frameCallbackData->frameTimelines[index].vsyncId; + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); + return frameCallbackData->frameTimelines[index].id; } int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime( const AChoreographerFrameCallbackData* data, size_t index) { @@ -671,8 +659,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); - return frameCallbackData->frameTimelines[index].expectedPresentTimeNanos; + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); + return frameCallbackData->frameTimelines[index].expectedPresentTime; } int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline( const AChoreographerFrameCallbackData* data, size_t index) { @@ -680,8 +668,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds"); - return frameCallbackData->frameTimelines[index].deadlineNanos; + LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); + return frameCallbackData->frameTimelines[index].deadlineTimestamp; } AChoreographer* AChoreographer_create() { diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 2bdcaf6ad0..e07eae79c8 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -355,14 +355,7 @@ void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp std::lock_guard lock(mMutex); LOG_FATAL_IF(!mVSyncState); - const int64_t vsyncId = [&] { - if (mTokenManager != nullptr) { - return mTokenManager->generateTokenForPredictions( - {timestamp, deadlineTimestamp, expectedVSyncTimestamp}); - } - return FrameTimelineInfo::INVALID_VSYNC_ID; - }(); - + const int64_t vsyncId = generateToken(timestamp, deadlineTimestamp, expectedVSyncTimestamp); mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count, expectedVSyncTimestamp, deadlineTimestamp, vsyncId)); mCondition.notify_all(); @@ -567,12 +560,48 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, } } +int64_t EventThread::generateToken(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, + nsecs_t deadlineTimestamp) const { + if (mTokenManager != nullptr) { + return mTokenManager->generateTokenForPredictions( + {timestamp, deadlineTimestamp, expectedVSyncTimestamp}); + } + return FrameTimelineInfo::INVALID_VSYNC_ID; +} + +void EventThread::generateFrameTimeline(DisplayEventReceiver::Event& event) const { + // Add 1 to ensure the preferredFrameTimelineIndex entry (when multiplier == 0) is included. + for (int multiplier = -DisplayEventReceiver::kFrameTimelinesLength + 1, currentIndex = 0; + currentIndex < DisplayEventReceiver::kFrameTimelinesLength; multiplier++) { + nsecs_t deadline = event.vsync.deadlineTimestamp + multiplier * event.vsync.frameInterval; + // Valid possible frame timelines must have future values. + if (deadline > event.header.timestamp) { + if (multiplier == 0) { + event.vsync.preferredFrameTimelineIndex = currentIndex; + event.vsync.frameTimelines[currentIndex] = + {.vsyncId = event.vsync.vsyncId, + .deadlineTimestamp = event.vsync.deadlineTimestamp, + .expectedVSyncTimestamp = event.vsync.expectedVSyncTimestamp}; + } else { + nsecs_t expectedVSync = + event.vsync.expectedVSyncTimestamp + multiplier * event.vsync.frameInterval; + event.vsync.frameTimelines[currentIndex] = + {.vsyncId = generateToken(event.header.timestamp, expectedVSync, deadline), + .deadlineTimestamp = deadline, + .expectedVSyncTimestamp = expectedVSync}; + } + currentIndex++; + } + } +} + void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, const DisplayEventConsumers& consumers) { for (const auto& consumer : consumers) { DisplayEventReceiver::Event copy = event; if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { copy.vsync.frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid); + generateFrameTimeline(copy); } switch (consumer->postEvent(copy)) { case NO_ERROR: diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 9265a25b86..73ae5dc9e3 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -204,6 +204,10 @@ private: void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, nsecs_t deadlineTimestamp) override; + int64_t generateToken(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp, + nsecs_t deadlineTimestamp) const; + void generateFrameTimeline(DisplayEventReceiver::Event& event) const; + const std::unique_ptr mVSyncSource GUARDED_BY(mMutex); frametimeline::TokenManager* const mTokenManager; diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 28d0222829..cb690aa0e4 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -28,6 +28,7 @@ #include "AsyncCallRecorder.h" #include "DisplayHardware/DisplayMode.h" +#include "FrameTimeline.h" #include "Scheduler/EventThread.h" using namespace std::chrono_literals; @@ -96,6 +97,8 @@ protected: ConnectionEventRecorder& connectionEventRecorder, nsecs_t expectedTimestamp, unsigned expectedCount); void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount); + void expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp, + nsecs_t preferredDeadline); void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, bool expectedConnected); void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, @@ -120,6 +123,7 @@ protected: std::unique_ptr mThread; sp mConnection; sp mThrottledConnection; + std::unique_ptr mTokenManager; static constexpr uid_t mConnectionUid = 443; static constexpr uid_t mThrottledConnectionUid = 177; @@ -173,8 +177,8 @@ void EventThreadTest::createThread(std::unique_ptr source) { return VSYNC_PERIOD.count(); }; - mThread = std::make_unique(std::move(source), - /*tokenManager=*/nullptr, + mTokenManager = std::make_unique(); + mThread = std::make_unique(std::move(source), mTokenManager.get(), mInterceptVSyncCallRecorder.getInvocable(), throttleVsync, getVsyncPeriod); @@ -247,6 +251,36 @@ void EventThreadTest::expectVsyncEventReceivedByConnection(nsecs_t expectedTimes expectedCount); } +void EventThreadTest::expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp, + nsecs_t preferredDeadline) { + auto args = mConnectionEventCallRecorder.waitForCall(); + ASSERT_TRUE(args.has_value()) << " did not receive an event for timestamp " + << expectedTimestamp; + const auto& event = std::get<0>(args.value()); + for (int i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) { + if (i > 0) { + EXPECT_GT(event.vsync.frameTimelines[i].deadlineTimestamp, + event.vsync.frameTimelines[i - 1].deadlineTimestamp) + << "Deadline timestamp out of order for frame timeline " << i; + EXPECT_GT(event.vsync.frameTimelines[i].expectedVSyncTimestamp, + event.vsync.frameTimelines[i - 1].expectedVSyncTimestamp) + << "Expected vsync timestamp out of order for frame timeline " << i; + } + if (event.vsync.frameTimelines[i].deadlineTimestamp == preferredDeadline) { + EXPECT_EQ(i, event.vsync.preferredFrameTimelineIndex) + << "Preferred frame timeline index should be " << i; + // For the platform-preferred frame timeline, the vsync ID is 0 because the first frame + // timeline is made before the rest. + EXPECT_EQ(0, event.vsync.frameTimelines[i].vsyncId) + << "Vsync ID incorrect for frame timeline " << i; + } else { + // Vsync ID 0 is used for the preferred frame timeline. + EXPECT_EQ(i + 1, event.vsync.frameTimelines[i].vsyncId) + << "Vsync ID incorrect for frame timeline " << i; + } + } +} + void EventThreadTest::expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, bool expectedConnected) { auto args = mConnectionEventCallRecorder.waitForCall(); @@ -344,6 +378,19 @@ TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) { expectVSyncSetEnabledCallReceived(false); } +TEST_F(EventThreadTest, requestNextVsyncEventFrameTimelinesCorrect) { + // Signal that we want the next vsync event to be posted to the connection + mThread->requestNextVsync(mConnection); + + expectVSyncSetEnabledCallReceived(true); + + // Use the received callback to signal a vsync event. + // The interceptor should receive the event, as well as the connection. + mCallback->onVSyncEvent(123, 456, 789); + expectInterceptCallReceived(123); + expectVsyncEventFrameTimelinesCorrect(123, 789); +} + TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) { // Create a first connection, register it, and request a vsync rate of zero. ConnectionEventRecorder firstConnectionEventRecorder{0}; -- cgit v1.2.3-59-g8ed1b From 08c4fd4ecd0484e5993d6f34638224cc17c30244 Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Wed, 27 Oct 2021 19:06:56 -0700 Subject: Obsoleted VsyncEventData.expectedPresentTime. It was obsoleted after plumbing multiple frame timelines which each have expected present time. Bug: 198192508 Test: atest ChoreographerNativeTest Change-Id: Ib39f8093ff89c9f7831cc40375d7a0a5ae9408dc --- libs/gui/DisplayEventDispatcher.cpp | 1 - libs/gui/include/gui/DisplayEventDispatcher.h | 3 --- 2 files changed, 4 deletions(-) (limited to 'libs/gui/DisplayEventDispatcher.cpp') diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index c986b82fd8..420246a064 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -166,7 +166,6 @@ bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, outVsyncEventData->id = ev.vsync.vsyncId; outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp; outVsyncEventData->frameInterval = ev.vsync.frameInterval; - outVsyncEventData->expectedPresentTime = ev.vsync.expectedVSyncTimestamp; outVsyncEventData->preferredFrameTimelineIndex = ev.vsync.preferredFrameTimelineIndex; populateFrameTimelines(ev, outVsyncEventData); diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index 92c89b8bde..db1b875982 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -35,9 +35,6 @@ struct VsyncEventData { // The current frame interval in ns when this frame was scheduled. int64_t frameInterval = 0; - // The anticipated Vsync present time. - int64_t expectedPresentTime = 0; - struct FrameTimeline { // The Vsync Id corresponsing to this vsync event. This will be used to // populate ISurfaceComposer::setFrameTimelineVsync and -- cgit v1.2.3-59-g8ed1b From 18c3437b13645962af487703b15815f93e8ee565 Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Thu, 20 Jan 2022 13:57:18 -0800 Subject: Split VsyncEventData from DisplayEventDispatcher. Bug: 205721584 Test: atest libsurfaceflinger_unittest Change-Id: I51b18ed356ae7a29f8a88634346c0025321dbe08 --- libs/gui/Android.bp | 1 + libs/gui/DisplayEventDispatcher.cpp | 11 ++-- libs/gui/VsyncEventData.cpp | 76 ++++++++++++++++++++++ libs/gui/include/gui/DisplayEventDispatcher.h | 35 ---------- libs/gui/include/gui/DisplayEventReceiver.h | 6 +- libs/gui/include/gui/VsyncEventData.h | 74 +++++++++++++++++++++ libs/gui/tests/Android.bp | 1 + libs/gui/tests/VsyncEventData_test.cpp | 75 +++++++++++++++++++++ libs/nativedisplay/AChoreographer.cpp | 4 +- services/surfaceflinger/Scheduler/EventThread.cpp | 4 +- .../tests/unittests/EventThreadTest.cpp | 2 +- 11 files changed, 240 insertions(+), 49 deletions(-) create mode 100644 libs/gui/VsyncEventData.cpp create mode 100644 libs/gui/include/gui/VsyncEventData.h create mode 100644 libs/gui/tests/VsyncEventData_test.cpp (limited to 'libs/gui/DisplayEventDispatcher.cpp') diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index ec3587b79a..e17b2c8af7 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -198,6 +198,7 @@ cc_library_shared { "SurfaceComposerClient.cpp", "SyncFeatures.cpp", "TransactionTracing.cpp", + "VsyncEventData.cpp", "view/Surface.cpp", "WindowInfosListenerReporter.cpp", "bufferqueue/1.0/B2HProducerListener.cpp", diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index ee8008270e..26db59bcff 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -148,14 +148,13 @@ int DisplayEventDispatcher::handleEvent(int, int events, void*) { void DisplayEventDispatcher::populateFrameTimelines(const DisplayEventReceiver::Event& event, VsyncEventData* outVsyncEventData) const { - for (size_t i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) { + for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { DisplayEventReceiver::Event::VSync::FrameTimeline receiverTimeline = event.vsync.frameTimelines[i]; - outVsyncEventData->frameTimelines[i] = {.id = receiverTimeline.vsyncId, - .deadlineTimestamp = - receiverTimeline.deadlineTimestamp, - .expectedPresentTime = - receiverTimeline.expectedVSyncTimestamp}; + outVsyncEventData->frameTimelines[i] = + VsyncEventData::FrameTimeline(receiverTimeline.vsyncId, + receiverTimeline.deadlineTimestamp, + receiverTimeline.expectedVSyncTimestamp); } } diff --git a/libs/gui/VsyncEventData.cpp b/libs/gui/VsyncEventData.cpp new file mode 100644 index 0000000000..aad81d0198 --- /dev/null +++ b/libs/gui/VsyncEventData.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 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. + */ + +#include "gui/VsyncEventData.h" +#include +#include +#include +#include +#include + +namespace android::gui { + +status_t VsyncEventData::readFromParcel(const Parcel* parcel) { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + + SAFE_PARCEL(parcel->readInt64, &id) + SAFE_PARCEL(parcel->readInt64, &deadlineTimestamp); + SAFE_PARCEL(parcel->readInt64, &frameInterval); + + uint64_t uintPreferredFrameTimelineIndex; + SAFE_PARCEL(parcel->readUint64, &uintPreferredFrameTimelineIndex); + preferredFrameTimelineIndex = static_cast(uintPreferredFrameTimelineIndex); + + std::vector timelines; + SAFE_PARCEL(parcel->readParcelableVector, &timelines); + std::copy_n(timelines.begin(), timelines.size(), frameTimelines.begin()); + + return OK; +} +status_t VsyncEventData::writeToParcel(Parcel* parcel) const { + SAFE_PARCEL(parcel->writeInt64, id) + SAFE_PARCEL(parcel->writeInt64, deadlineTimestamp); + SAFE_PARCEL(parcel->writeInt64, frameInterval); + SAFE_PARCEL(parcel->writeUint64, preferredFrameTimelineIndex); + SAFE_PARCEL(parcel->writeParcelableVector, + std::vector(frameTimelines.begin(), frameTimelines.end())); + + return OK; +} +status_t VsyncEventData::FrameTimeline::readFromParcel(const Parcel* parcel) { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + + SAFE_PARCEL(parcel->readInt64, &id) + SAFE_PARCEL(parcel->readInt64, &deadlineTimestamp); + SAFE_PARCEL(parcel->readInt64, &expectedPresentTime); + + return OK; +} +status_t VsyncEventData::FrameTimeline::writeToParcel(Parcel* parcel) const { + SAFE_PARCEL(parcel->writeInt64, id); + SAFE_PARCEL(parcel->writeInt64, deadlineTimestamp); + SAFE_PARCEL(parcel->writeInt64, expectedPresentTime); + + return OK; +} + +}; // namespace android::gui diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index 40621ddb15..71968fa59f 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -17,45 +17,10 @@ #include #include #include -#include namespace android { using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; -struct VsyncEventData { - // The Vsync Id corresponsing to this vsync event. This will be used to - // populate ISurfaceComposer::setFrameTimelineVsync and - // SurfaceComposerClient::setFrameTimelineVsync - int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID; - - // The deadline in CLOCK_MONOTONIC that the app needs to complete its - // frame by (both on the CPU and the GPU) - int64_t deadlineTimestamp = std::numeric_limits::max(); - - // The current frame interval in ns when this frame was scheduled. - int64_t frameInterval = 0; - - struct FrameTimeline { - // The Vsync Id corresponsing to this vsync event. This will be used to - // populate ISurfaceComposer::setFrameTimelineVsync and - // SurfaceComposerClient::setFrameTimelineVsync - int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID; - - // The deadline in CLOCK_MONOTONIC that the app needs to complete its - // frame by (both on the CPU and the GPU) - int64_t deadlineTimestamp = std::numeric_limits::max(); - - // The anticipated Vsync present time. - int64_t expectedPresentTime = 0; - }; - - // Sorted possible frame timelines. - std::array frameTimelines; - - // Index into the frameTimelines that represents the platform's preferred frame timeline. - size_t preferredFrameTimelineIndex = std::numeric_limits::max(); -}; - class DisplayEventDispatcher : public LooperCallback { public: explicit DisplayEventDispatcher( diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index 456bbfb611..db41c32549 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -26,6 +26,7 @@ #include #include +#include // ---------------------------------------------------------------------------- @@ -34,6 +35,7 @@ namespace android { // ---------------------------------------------------------------------------- using gui::IDisplayEventConnection; +using gui::VsyncEventData; namespace gui { class BitTube; @@ -49,8 +51,6 @@ static inline constexpr uint32_t fourcc(char c1, char c2, char c3, char c4) { // ---------------------------------------------------------------------------- class DisplayEventReceiver { public: - // Max amount of frame timelines is arbitrarily set to be reasonable. - static constexpr int64_t kFrameTimelinesLength = 7; enum { DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'), @@ -85,7 +85,7 @@ public: nsecs_t expectedVSyncTimestamp __attribute__((aligned(8))); nsecs_t deadlineTimestamp __attribute__((aligned(8))); int64_t vsyncId; - } frameTimelines[kFrameTimelinesLength]; + } frameTimelines[VsyncEventData::kFrameTimelinesLength]; }; struct Hotplug { diff --git a/libs/gui/include/gui/VsyncEventData.h b/libs/gui/include/gui/VsyncEventData.h new file mode 100644 index 0000000000..abac61c334 --- /dev/null +++ b/libs/gui/include/gui/VsyncEventData.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 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 + +#include + +namespace android::gui { +struct VsyncEventData : public Parcelable { + // Max amount of frame timelines is arbitrarily set to be reasonable. + static constexpr int64_t kFrameTimelinesLength = 7; + + // The Vsync Id corresponsing to this vsync event. This will be used to + // populate ISurfaceComposer::setFrameTimelineVsync and + // SurfaceComposerClient::setFrameTimelineVsync + // TODO(b/198191703): Remove when JNI DisplayEventReceiver uses frameTimelines array. + int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID; + + // The deadline in CLOCK_MONOTONIC that the app needs to complete its + // frame by (both on the CPU and the GPU) + // TODO(b/198191703): Remove when JNI DisplayEventReceiver uses frameTimelines array. + int64_t deadlineTimestamp = std::numeric_limits::max(); + + // The current frame interval in ns when this frame was scheduled. + int64_t frameInterval = 0; + + struct FrameTimeline : public Parcelable { + FrameTimeline() = default; + FrameTimeline(int64_t id, int64_t deadlineTimestamp, int64_t expectedPresentTime) + : id(id), + deadlineTimestamp(deadlineTimestamp), + expectedPresentTime(expectedPresentTime) {} + + // The Vsync Id corresponsing to this vsync event. This will be used to + // populate ISurfaceComposer::setFrameTimelineVsync and + // SurfaceComposerClient::setFrameTimelineVsync + int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID; + + // The deadline in CLOCK_MONOTONIC that the app needs to complete its + // frame by (both on the CPU and the GPU) + int64_t deadlineTimestamp = std::numeric_limits::max(); + + // The anticipated Vsync present time. + int64_t expectedPresentTime = 0; + + status_t readFromParcel(const Parcel*) override; + status_t writeToParcel(Parcel*) const override; + }; + + // Sorted possible frame timelines. + std::array frameTimelines; + + // Index into the frameTimelines that represents the platform's preferred frame timeline. + size_t preferredFrameTimelineIndex = std::numeric_limits::max(); + + status_t readFromParcel(const Parcel*) override; + status_t writeToParcel(Parcel*) const override; +}; +} // namespace android::gui diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 6dd1073879..e58543a245 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -44,6 +44,7 @@ cc_test { "SurfaceTextureMultiContextGL_test.cpp", "Surface_test.cpp", "TextureRenderer.cpp", + "VsyncEventData_test.cpp", "WindowInfo_test.cpp", ], diff --git a/libs/gui/tests/VsyncEventData_test.cpp b/libs/gui/tests/VsyncEventData_test.cpp new file mode 100644 index 0000000000..a670d42fe3 --- /dev/null +++ b/libs/gui/tests/VsyncEventData_test.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 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. + */ + +#include + +#include + +#include + +namespace android { + +using gui::VsyncEventData; +using FrameTimeline = gui::VsyncEventData::FrameTimeline; + +namespace test { + +TEST(VsyncEventData, Parcelling) { + VsyncEventData data; + data.id = 123; + data.deadlineTimestamp = 456; + data.frameInterval = 789; + data.preferredFrameTimelineIndex = 1; + FrameTimeline timeline0 = FrameTimeline(1, 2, 3); + FrameTimeline timeline1 = FrameTimeline(4, 5, 6); + data.frameTimelines[0] = timeline0; + data.frameTimelines[1] = timeline1; + + Parcel p; + data.writeToParcel(&p); + p.setDataPosition(0); + + VsyncEventData data2; + data2.readFromParcel(&p); + ASSERT_EQ(data.id, data2.id); + ASSERT_EQ(data.deadlineTimestamp, data2.deadlineTimestamp); + ASSERT_EQ(data.frameInterval, data2.frameInterval); + ASSERT_EQ(data.preferredFrameTimelineIndex, data2.preferredFrameTimelineIndex); + for (int i = 0; i < data.frameTimelines.size(); i++) { + ASSERT_EQ(data.frameTimelines[i].id, data2.frameTimelines[i].id); + ASSERT_EQ(data.frameTimelines[i].deadlineTimestamp, + data2.frameTimelines[i].deadlineTimestamp); + ASSERT_EQ(data.frameTimelines[i].expectedPresentTime, + data2.frameTimelines[i].expectedPresentTime); + } +} + +TEST(FrameTimeline, Parcelling) { + FrameTimeline timeline = FrameTimeline(1, 2, 3); + + Parcel p; + timeline.writeToParcel(&p); + p.setDataPosition(0); + + FrameTimeline timeline2; + timeline2.readFromParcel(&p); + ASSERT_EQ(timeline.id, timeline2.id); + ASSERT_EQ(timeline.deadlineTimestamp, timeline2.deadlineTimestamp); + ASSERT_EQ(timeline.expectedPresentTime, timeline2.expectedPresentTime); +} + +} // namespace test +} // namespace android diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index d90ee57322..b182a4a6f1 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -73,6 +73,7 @@ inline const char* toString(bool value) { } // namespace namespace android { +using gui::VsyncEventData; struct FrameCallback { AChoreographer_frameCallback callback; @@ -102,8 +103,7 @@ class Choreographer; struct ChoreographerFrameCallbackDataImpl { int64_t frameTimeNanos{0}; - std::array - frameTimelines; + std::array frameTimelines; size_t preferredFrameTimelineIndex; diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index c9ab96592e..b57ffceb27 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -563,8 +563,8 @@ int64_t EventThread::generateToken(nsecs_t timestamp, nsecs_t deadlineTimestamp, void EventThread::generateFrameTimeline(DisplayEventReceiver::Event& event) const { // Add 1 to ensure the preferredFrameTimelineIndex entry (when multiplier == 0) is included. - for (int multiplier = -DisplayEventReceiver::kFrameTimelinesLength + 1, currentIndex = 0; - currentIndex < DisplayEventReceiver::kFrameTimelinesLength; multiplier++) { + for (int multiplier = -VsyncEventData::kFrameTimelinesLength + 1, currentIndex = 0; + currentIndex < VsyncEventData::kFrameTimelinesLength; multiplier++) { nsecs_t deadline = event.vsync.deadlineTimestamp + multiplier * event.vsync.frameInterval; // Valid possible frame timelines must have future values. if (deadline > event.header.timestamp) { diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 57cb5cf441..7761828849 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -257,7 +257,7 @@ void EventThreadTest::expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTime ASSERT_TRUE(args.has_value()) << " did not receive an event for timestamp " << expectedTimestamp; const auto& event = std::get<0>(args.value()); - for (int i = 0; i < DisplayEventReceiver::kFrameTimelinesLength; i++) { + for (int i = 0; i < gui::VsyncEventData::kFrameTimelinesLength; i++) { auto prediction = mTokenManager->getPredictionsForToken(event.vsync.frameTimelines[i].vsyncId); EXPECT_TRUE(prediction.has_value()); -- cgit v1.2.3-59-g8ed1b From b9c5a77a31d16212d87335abd5909d4d78a2b981 Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Fri, 4 Feb 2022 21:17:37 -0800 Subject: Use VsyncEventData in DisplayEventReceiver::Event. Clean-up that re-uses VsyncEventData so it's easier to maintain. The ParcelableVsyncEventData is used in AIDL. It is separated from VsyncEventData because of the union in DisplayEventReceiver::Event and Parcelable has non-trivial constructors. Bug: 218563993 Test: atest ChoreographerNativeTest Test: atest libsurfaceflinger_unittest Test: atest libgui_test Change-Id: I3ebeb1c7826300c27c4a12d4dba6fbd16305e9e1 --- libs/gui/DisplayEventDispatcher.cpp | 21 +--- libs/gui/DisplayEventReceiver.cpp | 7 +- libs/gui/VsyncEventData.cpp | 60 +++++------- .../aidl/android/gui/IDisplayEventConnection.aidl | 4 +- .../aidl/android/gui/ParcelableVsyncEventData.aidl | 19 ++++ libs/gui/aidl/android/gui/VsyncEventData.aidl | 19 ---- libs/gui/include/gui/DisplayEventReceiver.h | 14 +-- libs/gui/include/gui/VsyncEventData.h | 56 +++++------ libs/gui/tests/DisplayEventStructLayout_test.cpp | 30 +++++- libs/gui/tests/VsyncEventData_test.cpp | 53 ++++------ libs/nativedisplay/AChoreographer.cpp | 23 ++--- services/surfaceflinger/Scheduler/EventThread.cpp | 109 +++++++++------------ services/surfaceflinger/Scheduler/EventThread.h | 20 ++-- services/surfaceflinger/Scheduler/MessageQueue.cpp | 3 +- .../tests/DisplayEventReceiver_test.cpp | 15 +-- .../surfaceflinger/tests/LayerCallback_test.cpp | 5 +- .../tests/unittests/DispSyncSourceTest.cpp | 10 +- .../tests/unittests/EventThreadTest.cpp | 65 ++++++------ 18 files changed, 239 insertions(+), 294 deletions(-) create mode 100644 libs/gui/aidl/android/gui/ParcelableVsyncEventData.aidl delete mode 100644 libs/gui/aidl/android/gui/VsyncEventData.aidl (limited to 'libs/gui/DisplayEventDispatcher.cpp') diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index 26db59bcff..39d380d9e1 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -126,7 +126,7 @@ int DisplayEventDispatcher::handleEvent(int, int events, void*) { ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 ", displayId=%s, count=%d, vsyncId=%" PRId64, this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount, - vsyncEventData.id); + vsyncEventData.preferredVsyncId()); mWaitingForVsync = false; mLastVsyncCount = vsyncCount; dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData); @@ -146,18 +146,6 @@ int DisplayEventDispatcher::handleEvent(int, int events, void*) { return 1; // keep the callback } -void DisplayEventDispatcher::populateFrameTimelines(const DisplayEventReceiver::Event& event, - VsyncEventData* outVsyncEventData) const { - for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { - DisplayEventReceiver::Event::VSync::FrameTimeline receiverTimeline = - event.vsync.frameTimelines[i]; - outVsyncEventData->frameTimelines[i] = - VsyncEventData::FrameTimeline(receiverTimeline.vsyncId, - receiverTimeline.deadlineTimestamp, - receiverTimeline.expectedVSyncTimestamp); - } -} - bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, uint32_t* outCount, @@ -178,12 +166,7 @@ bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, *outTimestamp = ev.header.timestamp; *outDisplayId = ev.header.displayId; *outCount = ev.vsync.count; - outVsyncEventData->id = ev.vsync.vsyncId; - outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp; - outVsyncEventData->frameInterval = ev.vsync.frameInterval; - outVsyncEventData->preferredFrameTimelineIndex = - ev.vsync.preferredFrameTimelineIndex; - populateFrameTimelines(ev, outVsyncEventData); + *outVsyncEventData = ev.vsync.vsyncData; break; case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected); diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp index 36e7d80d5e..ec0be87340 100644 --- a/libs/gui/DisplayEventReceiver.cpp +++ b/libs/gui/DisplayEventReceiver.cpp @@ -80,15 +80,14 @@ status_t DisplayEventReceiver::requestNextVsync() { return NO_INIT; } -status_t DisplayEventReceiver::getLatestVsyncEventData(VsyncEventData* outVsyncEventData) const { +status_t DisplayEventReceiver::getLatestVsyncEventData( + ParcelableVsyncEventData* outVsyncEventData) const { if (mEventConnection != nullptr) { - VsyncEventData vsyncEventData; - auto status = mEventConnection->getLatestVsyncEventData(&vsyncEventData); + auto status = mEventConnection->getLatestVsyncEventData(outVsyncEventData); if (!status.isOk()) { ALOGE("Failed to get latest vsync event data: %s", status.exceptionMessage().c_str()); return status.transactionError(); } - *outVsyncEventData = vsyncEventData; return NO_ERROR; } return NO_INIT; diff --git a/libs/gui/VsyncEventData.cpp b/libs/gui/VsyncEventData.cpp index aad81d0198..23f0921e99 100644 --- a/libs/gui/VsyncEventData.cpp +++ b/libs/gui/VsyncEventData.cpp @@ -23,52 +23,46 @@ namespace android::gui { -status_t VsyncEventData::readFromParcel(const Parcel* parcel) { +int64_t VsyncEventData::preferredVsyncId() const { + return frameTimelines[preferredFrameTimelineIndex].vsyncId; +} + +int64_t VsyncEventData::preferredDeadlineTimestamp() const { + return frameTimelines[preferredFrameTimelineIndex].deadlineTimestamp; +} + +int64_t VsyncEventData::preferredExpectedPresentationTime() const { + return frameTimelines[preferredFrameTimelineIndex].expectedPresentationTime; +} + +status_t ParcelableVsyncEventData::readFromParcel(const Parcel* parcel) { if (parcel == nullptr) { ALOGE("%s: Null parcel", __func__); return BAD_VALUE; } - SAFE_PARCEL(parcel->readInt64, &id) - SAFE_PARCEL(parcel->readInt64, &deadlineTimestamp); - SAFE_PARCEL(parcel->readInt64, &frameInterval); + SAFE_PARCEL(parcel->readInt64, &vsync.frameInterval); uint64_t uintPreferredFrameTimelineIndex; SAFE_PARCEL(parcel->readUint64, &uintPreferredFrameTimelineIndex); - preferredFrameTimelineIndex = static_cast(uintPreferredFrameTimelineIndex); - - std::vector timelines; - SAFE_PARCEL(parcel->readParcelableVector, &timelines); - std::copy_n(timelines.begin(), timelines.size(), frameTimelines.begin()); + vsync.preferredFrameTimelineIndex = static_cast(uintPreferredFrameTimelineIndex); - return OK; -} -status_t VsyncEventData::writeToParcel(Parcel* parcel) const { - SAFE_PARCEL(parcel->writeInt64, id) - SAFE_PARCEL(parcel->writeInt64, deadlineTimestamp); - SAFE_PARCEL(parcel->writeInt64, frameInterval); - SAFE_PARCEL(parcel->writeUint64, preferredFrameTimelineIndex); - SAFE_PARCEL(parcel->writeParcelableVector, - std::vector(frameTimelines.begin(), frameTimelines.end())); - - return OK; -} -status_t VsyncEventData::FrameTimeline::readFromParcel(const Parcel* parcel) { - if (parcel == nullptr) { - ALOGE("%s: Null parcel", __func__); - return BAD_VALUE; + for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { + SAFE_PARCEL(parcel->readInt64, &vsync.frameTimelines[i].vsyncId); + SAFE_PARCEL(parcel->readInt64, &vsync.frameTimelines[i].deadlineTimestamp); + SAFE_PARCEL(parcel->readInt64, &vsync.frameTimelines[i].expectedPresentationTime); } - SAFE_PARCEL(parcel->readInt64, &id) - SAFE_PARCEL(parcel->readInt64, &deadlineTimestamp); - SAFE_PARCEL(parcel->readInt64, &expectedPresentTime); - return OK; } -status_t VsyncEventData::FrameTimeline::writeToParcel(Parcel* parcel) const { - SAFE_PARCEL(parcel->writeInt64, id); - SAFE_PARCEL(parcel->writeInt64, deadlineTimestamp); - SAFE_PARCEL(parcel->writeInt64, expectedPresentTime); +status_t ParcelableVsyncEventData::writeToParcel(Parcel* parcel) const { + SAFE_PARCEL(parcel->writeInt64, vsync.frameInterval); + SAFE_PARCEL(parcel->writeUint64, vsync.preferredFrameTimelineIndex); + for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { + SAFE_PARCEL(parcel->writeInt64, vsync.frameTimelines[i].vsyncId); + SAFE_PARCEL(parcel->writeInt64, vsync.frameTimelines[i].deadlineTimestamp); + SAFE_PARCEL(parcel->writeInt64, vsync.frameTimelines[i].expectedPresentationTime); + } return OK; } diff --git a/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl b/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl index e9a6a0c642..9781ca96f4 100644 --- a/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl +++ b/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl @@ -17,7 +17,7 @@ package android.gui; import android.gui.BitTube; -import android.gui.VsyncEventData; +import android.gui.ParcelableVsyncEventData; /** @hide */ interface IDisplayEventConnection { @@ -43,5 +43,5 @@ interface IDisplayEventConnection { /* * getLatestVsyncEventData() gets the latest vsync event data. */ - VsyncEventData getLatestVsyncEventData(); + ParcelableVsyncEventData getLatestVsyncEventData(); } diff --git a/libs/gui/aidl/android/gui/ParcelableVsyncEventData.aidl b/libs/gui/aidl/android/gui/ParcelableVsyncEventData.aidl new file mode 100644 index 0000000000..ba76671f8f --- /dev/null +++ b/libs/gui/aidl/android/gui/ParcelableVsyncEventData.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2021 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. + */ + +package android.gui; + +parcelable ParcelableVsyncEventData cpp_header "gui/VsyncEventData.h"; diff --git a/libs/gui/aidl/android/gui/VsyncEventData.aidl b/libs/gui/aidl/android/gui/VsyncEventData.aidl deleted file mode 100644 index 7343515d25..0000000000 --- a/libs/gui/aidl/android/gui/VsyncEventData.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2021 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. - */ - -package android.gui; - -parcelable VsyncEventData cpp_header "gui/VsyncEventData.h"; diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index 4e04db3cde..ddc109e52a 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -35,6 +35,7 @@ namespace android { // ---------------------------------------------------------------------------- using gui::IDisplayEventConnection; +using gui::ParcelableVsyncEventData; using gui::VsyncEventData; namespace gui { @@ -76,16 +77,7 @@ public: struct VSync { uint32_t count; - nsecs_t expectedVSyncTimestamp __attribute__((aligned(8))); - nsecs_t deadlineTimestamp __attribute__((aligned(8))); - nsecs_t frameInterval __attribute__((aligned(8))); - int64_t vsyncId; - size_t preferredFrameTimelineIndex __attribute__((aligned(8))); - struct FrameTimeline { - nsecs_t expectedVSyncTimestamp __attribute__((aligned(8))); - nsecs_t deadlineTimestamp __attribute__((aligned(8))); - int64_t vsyncId; - } frameTimelines[VsyncEventData::kFrameTimelinesLength]; + VsyncEventData vsyncData; }; struct Hotplug { @@ -175,7 +167,7 @@ public: /** * getLatestVsyncEventData() gets the latest vsync event data. */ - status_t getLatestVsyncEventData(VsyncEventData* outVsyncEventData) const; + status_t getLatestVsyncEventData(ParcelableVsyncEventData* outVsyncEventData) const; private: sp mEventConnection; diff --git a/libs/gui/include/gui/VsyncEventData.h b/libs/gui/include/gui/VsyncEventData.h index abac61c334..8e99539fe9 100644 --- a/libs/gui/include/gui/VsyncEventData.h +++ b/libs/gui/include/gui/VsyncEventData.h @@ -21,52 +21,44 @@ #include namespace android::gui { -struct VsyncEventData : public Parcelable { +// Plain Old Data (POD) vsync data structure. For example, it can be easily used in the +// DisplayEventReceiver::Event union. +struct VsyncEventData { // Max amount of frame timelines is arbitrarily set to be reasonable. static constexpr int64_t kFrameTimelinesLength = 7; - // The Vsync Id corresponsing to this vsync event. This will be used to - // populate ISurfaceComposer::setFrameTimelineVsync and - // SurfaceComposerClient::setFrameTimelineVsync - // TODO(b/198191703): Remove when JNI DisplayEventReceiver uses frameTimelines array. - int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID; - - // The deadline in CLOCK_MONOTONIC that the app needs to complete its - // frame by (both on the CPU and the GPU) - // TODO(b/198191703): Remove when JNI DisplayEventReceiver uses frameTimelines array. - int64_t deadlineTimestamp = std::numeric_limits::max(); - // The current frame interval in ns when this frame was scheduled. - int64_t frameInterval = 0; + int64_t frameInterval; - struct FrameTimeline : public Parcelable { - FrameTimeline() = default; - FrameTimeline(int64_t id, int64_t deadlineTimestamp, int64_t expectedPresentTime) - : id(id), - deadlineTimestamp(deadlineTimestamp), - expectedPresentTime(expectedPresentTime) {} + // Index into the frameTimelines that represents the platform's preferred frame timeline. + uint32_t preferredFrameTimelineIndex; + struct alignas(8) FrameTimeline { // The Vsync Id corresponsing to this vsync event. This will be used to // populate ISurfaceComposer::setFrameTimelineVsync and // SurfaceComposerClient::setFrameTimelineVsync - int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID; + int64_t vsyncId; - // The deadline in CLOCK_MONOTONIC that the app needs to complete its - // frame by (both on the CPU and the GPU) - int64_t deadlineTimestamp = std::numeric_limits::max(); + // The deadline in CLOCK_MONOTONIC in nanos that the app needs to complete its + // frame by (both on the CPU and the GPU). + int64_t deadlineTimestamp; - // The anticipated Vsync present time. - int64_t expectedPresentTime = 0; + // The anticipated Vsync presentation time in nanos. + int64_t expectedPresentationTime; + } frameTimelines[kFrameTimelinesLength]; // Sorted possible frame timelines. - status_t readFromParcel(const Parcel*) override; - status_t writeToParcel(Parcel*) const override; - }; + // Gets the preferred frame timeline's vsync ID. + int64_t preferredVsyncId() const; - // Sorted possible frame timelines. - std::array frameTimelines; + // Gets the preferred frame timeline's deadline timestamp. + int64_t preferredDeadlineTimestamp() const; - // Index into the frameTimelines that represents the platform's preferred frame timeline. - size_t preferredFrameTimelineIndex = std::numeric_limits::max(); + // Gets the preferred frame timeline's expected vsync timestamp. + int64_t preferredExpectedPresentationTime() const; +}; + +struct ParcelableVsyncEventData : public Parcelable { + VsyncEventData vsync; status_t readFromParcel(const Parcel*) override; status_t writeToParcel(Parcel*) const override; diff --git a/libs/gui/tests/DisplayEventStructLayout_test.cpp b/libs/gui/tests/DisplayEventStructLayout_test.cpp index bcd39dbbf4..da88463d63 100644 --- a/libs/gui/tests/DisplayEventStructLayout_test.cpp +++ b/libs/gui/tests/DisplayEventStructLayout_test.cpp @@ -20,9 +20,10 @@ namespace android::test { #define CHECK_OFFSET(type, member, expected_offset) \ - static_assert((offsetof(type, member) == (expected_offset)), "") + static_assert((offsetof(type, member) == (expected_offset))) TEST(DisplayEventStructLayoutTest, TestEventAlignment) { + static_assert(std::is_pod::value); CHECK_OFFSET(DisplayEventReceiver::Event, vsync, 24); CHECK_OFFSET(DisplayEventReceiver::Event, hotplug, 24); CHECK_OFFSET(DisplayEventReceiver::Event, modeChange, 24); @@ -32,10 +33,29 @@ TEST(DisplayEventStructLayoutTest, TestEventAlignment) { CHECK_OFFSET(DisplayEventReceiver::Event::Header, timestamp, 16); CHECK_OFFSET(DisplayEventReceiver::Event::VSync, count, 0); - CHECK_OFFSET(DisplayEventReceiver::Event::VSync, expectedVSyncTimestamp, 8); - CHECK_OFFSET(DisplayEventReceiver::Event::VSync, deadlineTimestamp, 16); - CHECK_OFFSET(DisplayEventReceiver::Event::VSync, frameInterval, 24); - CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncId, 32); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameInterval, 8); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.preferredFrameTimelineIndex, 16); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameTimelines, 24); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameTimelines[0].vsyncId, 24); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncData.frameTimelines[0].deadlineTimestamp, + 32); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, + vsyncData.frameTimelines[0].expectedPresentationTime, 40); + // Also test the offsets of the last frame timeline. A loop is not used because the non-const + // index cannot be used in static_assert. + const int lastFrameTimelineOffset = /* Start of array */ 24 + + (VsyncEventData::kFrameTimelinesLength - 1) * /* Size of FrameTimeline */ 24; + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, + vsyncData.frameTimelines[VsyncEventData::kFrameTimelinesLength - 1].vsyncId, + lastFrameTimelineOffset); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, + vsyncData.frameTimelines[VsyncEventData::kFrameTimelinesLength - 1] + .deadlineTimestamp, + lastFrameTimelineOffset + 8); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, + vsyncData.frameTimelines[VsyncEventData::kFrameTimelinesLength - 1] + .expectedPresentationTime, + lastFrameTimelineOffset + 16); CHECK_OFFSET(DisplayEventReceiver::Event::Hotplug, connected, 0); diff --git a/libs/gui/tests/VsyncEventData_test.cpp b/libs/gui/tests/VsyncEventData_test.cpp index a670d42fe3..f114522951 100644 --- a/libs/gui/tests/VsyncEventData_test.cpp +++ b/libs/gui/tests/VsyncEventData_test.cpp @@ -22,54 +22,37 @@ namespace android { +using gui::ParcelableVsyncEventData; using gui::VsyncEventData; using FrameTimeline = gui::VsyncEventData::FrameTimeline; namespace test { -TEST(VsyncEventData, Parcelling) { - VsyncEventData data; - data.id = 123; - data.deadlineTimestamp = 456; - data.frameInterval = 789; - data.preferredFrameTimelineIndex = 1; - FrameTimeline timeline0 = FrameTimeline(1, 2, 3); - FrameTimeline timeline1 = FrameTimeline(4, 5, 6); - data.frameTimelines[0] = timeline0; - data.frameTimelines[1] = timeline1; +TEST(ParcelableVsyncEventData, Parcelling) { + ParcelableVsyncEventData data; + data.vsync.frameInterval = 789; + data.vsync.preferredFrameTimelineIndex = 1; + FrameTimeline timeline0 = FrameTimeline{1, 2, 3}; + FrameTimeline timeline1 = FrameTimeline{4, 5, 6}; + data.vsync.frameTimelines[0] = timeline0; + data.vsync.frameTimelines[1] = timeline1; Parcel p; data.writeToParcel(&p); p.setDataPosition(0); - VsyncEventData data2; + ParcelableVsyncEventData data2; data2.readFromParcel(&p); - ASSERT_EQ(data.id, data2.id); - ASSERT_EQ(data.deadlineTimestamp, data2.deadlineTimestamp); - ASSERT_EQ(data.frameInterval, data2.frameInterval); - ASSERT_EQ(data.preferredFrameTimelineIndex, data2.preferredFrameTimelineIndex); - for (int i = 0; i < data.frameTimelines.size(); i++) { - ASSERT_EQ(data.frameTimelines[i].id, data2.frameTimelines[i].id); - ASSERT_EQ(data.frameTimelines[i].deadlineTimestamp, - data2.frameTimelines[i].deadlineTimestamp); - ASSERT_EQ(data.frameTimelines[i].expectedPresentTime, - data2.frameTimelines[i].expectedPresentTime); + ASSERT_EQ(data.vsync.frameInterval, data2.vsync.frameInterval); + ASSERT_EQ(data.vsync.preferredFrameTimelineIndex, data2.vsync.preferredFrameTimelineIndex); + for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { + ASSERT_EQ(data.vsync.frameTimelines[i].vsyncId, data2.vsync.frameTimelines[i].vsyncId); + ASSERT_EQ(data.vsync.frameTimelines[i].deadlineTimestamp, + data2.vsync.frameTimelines[i].deadlineTimestamp); + ASSERT_EQ(data.vsync.frameTimelines[i].expectedPresentationTime, + data2.vsync.frameTimelines[i].expectedPresentationTime); } } -TEST(FrameTimeline, Parcelling) { - FrameTimeline timeline = FrameTimeline(1, 2, 3); - - Parcel p; - timeline.writeToParcel(&p); - p.setDataPosition(0); - - FrameTimeline timeline2; - timeline2.readFromParcel(&p); - ASSERT_EQ(timeline.id, timeline2.id); - ASSERT_EQ(timeline.deadlineTimestamp, timeline2.deadlineTimestamp); - ASSERT_EQ(timeline.expectedPresentTime, timeline2.expectedPresentTime); -} - } // namespace test } // namespace android diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index b182a4a6f1..3ce381b122 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -103,9 +103,7 @@ class Choreographer; struct ChoreographerFrameCallbackDataImpl { int64_t frameTimeNanos{0}; - std::array frameTimelines; - - size_t preferredFrameTimelineIndex; + VsyncEventData vsyncEventData; const Choreographer* choreographer; }; @@ -450,8 +448,7 @@ bool Choreographer::inCallback() const { ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const { return {.frameTimeNanos = timestamp, - .preferredFrameTimelineIndex = mLastVsyncEventData.preferredFrameTimelineIndex, - .frameTimelines = mLastVsyncEventData.frameTimelines, + .vsyncEventData = mLastVsyncEventData, .choreographer = this}; } @@ -634,7 +631,7 @@ size_t AChoreographerFrameCallbackData_getFrameTimelinesLength( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - return frameCallbackData->frameTimelines.size(); + return VsyncEventData::kFrameTimelinesLength; } size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex( const AChoreographerFrameCallbackData* data) { @@ -642,7 +639,7 @@ size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - return frameCallbackData->preferredFrameTimelineIndex; + return frameCallbackData->vsyncEventData.preferredFrameTimelineIndex; } AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId( const AChoreographerFrameCallbackData* data, size_t index) { @@ -650,8 +647,8 @@ AVsyncId AChoreographerFrameCallbackData_getFrameTimelineVsyncId( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); - return frameCallbackData->frameTimelines[index].id; + LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesLength, "Index out of bounds"); + return frameCallbackData->vsyncEventData.frameTimelines[index].vsyncId; } int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos( const AChoreographerFrameCallbackData* data, size_t index) { @@ -659,8 +656,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTimeNanos AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); - return frameCallbackData->frameTimelines[index].expectedPresentTime; + LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesLength, "Index out of bounds"); + return frameCallbackData->vsyncEventData.frameTimelines[index].expectedPresentationTime; } int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos( const AChoreographerFrameCallbackData* data, size_t index) { @@ -668,8 +665,8 @@ int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos( AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data); LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(), "Data is only valid in callback"); - LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelines.size(), "Index out of bounds"); - return frameCallbackData->frameTimelines[index].deadlineTimestamp; + LOG_ALWAYS_FATAL_IF(index >= VsyncEventData::kFrameTimelinesLength, "Index out of bounds"); + return frameCallbackData->vsyncEventData.frameTimelines[index].deadlineTimestamp; } AChoreographer* AChoreographer_create() { diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 2d0da4643d..5ba8a1b449 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -87,9 +87,10 @@ std::string toString(const DisplayEventReceiver::Event& event) { to_string(event.header.displayId).c_str(), event.hotplug.connected ? "connected" : "disconnected"); case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: - return StringPrintf("VSync{displayId=%s, count=%u, expectedVSyncTimestamp=%" PRId64 "}", + return StringPrintf("VSync{displayId=%s, count=%u, expectedPresentationTime=%" PRId64 + "}", to_string(event.header.displayId).c_str(), event.vsync.count, - event.vsync.expectedVSyncTimestamp); + event.vsync.vsyncData.preferredExpectedPresentationTime()); case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: return StringPrintf("ModeChanged{displayId=%s, modeId=%u}", to_string(event.header.displayId).c_str(), event.modeChange.modeId); @@ -107,13 +108,19 @@ DisplayEventReceiver::Event makeHotplug(PhysicalDisplayId displayId, nsecs_t tim } DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp, - uint32_t count, nsecs_t expectedVSyncTimestamp, + uint32_t count, nsecs_t expectedPresentationTime, nsecs_t deadlineTimestamp) { DisplayEventReceiver::Event event; event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp}; event.vsync.count = count; - event.vsync.expectedVSyncTimestamp = expectedVSyncTimestamp; - event.vsync.deadlineTimestamp = deadlineTimestamp; + event.vsync.vsyncData.preferredFrameTimelineIndex = 0; + // Temporarily store the current vsync information in frameTimelines[0], marked as + // platform-preferred. When the event is dispatched later, the frame interval at that time is + // used with this information to generate multiple frame timeline choices. + event.vsync.vsyncData.frameTimelines[0] = {.vsyncId = FrameTimelineInfo::INVALID_VSYNC_ID, + .deadlineTimestamp = deadlineTimestamp, + .expectedPresentationTime = + expectedPresentationTime}; return event; } @@ -186,9 +193,10 @@ binder::Status EventThreadConnection::requestNextVsync() { return binder::Status::ok(); } -binder::Status EventThreadConnection::getLatestVsyncEventData(VsyncEventData* outVsyncEventData) { +binder::Status EventThreadConnection::getLatestVsyncEventData( + ParcelableVsyncEventData* outVsyncEventData) { ATRACE_CALL(); - *outVsyncEventData = mEventThread->getLatestVsyncEventData(this); + outVsyncEventData->vsync = mEventThread->getLatestVsyncEventData(this); return binder::Status::ok(); } @@ -338,10 +346,16 @@ void EventThread::requestNextVsync(const sp& connection) VsyncEventData EventThread::getLatestVsyncEventData( const sp& connection) const { - nsecs_t frameInterval = mGetVsyncPeriodFunction(connection->mOwnerUid); VsyncEventData vsyncEventData; + nsecs_t frameInterval = mGetVsyncPeriodFunction(connection->mOwnerUid); vsyncEventData.frameInterval = frameInterval; - generateFrameTimeline(vsyncEventData, frameInterval, systemTime(SYSTEM_TIME_MONOTONIC)); + VSyncSource::VSyncData vsyncData; + { + std::lock_guard lock(mMutex); + vsyncData = mVSyncSource->getLatestVSyncData(); + } + generateFrameTimeline(vsyncEventData, frameInterval, systemTime(SYSTEM_TIME_MONOTONIC), + vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp); return vsyncEventData; } @@ -370,7 +384,7 @@ void EventThread::onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncDa LOG_FATAL_IF(!mVSyncState); mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count, - vsyncData.expectedVSyncTimestamp, + vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp)); mCondition.notify_all(); } @@ -518,7 +532,8 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, const sp& connection) const { const auto throttleVsync = [&] { return mThrottleVsyncCallback && - mThrottleVsyncCallback(event.vsync.expectedVSyncTimestamp, connection->mOwnerUid); + mThrottleVsyncCallback(event.vsync.vsyncData.preferredExpectedPresentationTime(), + connection->mOwnerUid); }; switch (event.header.type) { @@ -568,79 +583,49 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, } int64_t EventThread::generateToken(nsecs_t timestamp, nsecs_t deadlineTimestamp, - nsecs_t expectedVSyncTimestamp) const { + nsecs_t expectedPresentationTime) const { if (mTokenManager != nullptr) { return mTokenManager->generateTokenForPredictions( - {timestamp, deadlineTimestamp, expectedVSyncTimestamp}); + {timestamp, deadlineTimestamp, expectedPresentationTime}); } return FrameTimelineInfo::INVALID_VSYNC_ID; } -void EventThread::generateFrameTimeline( - nsecs_t frameInterval, nsecs_t timestamp, nsecs_t preferredExpectedVSyncTimestamp, - nsecs_t preferredDeadlineTimestamp, - std::function setPreferredFrameTimelineIndex, - std::function - setFrameTimeline) const { +void EventThread::generateFrameTimeline(VsyncEventData& outVsyncEventData, nsecs_t frameInterval, + nsecs_t timestamp, + nsecs_t preferredExpectedPresentationTime, + nsecs_t preferredDeadlineTimestamp) const { // Add 1 to ensure the preferredFrameTimelineIndex entry (when multiplier == 0) is included. for (int64_t multiplier = -VsyncEventData::kFrameTimelinesLength + 1, currentIndex = 0; currentIndex < VsyncEventData::kFrameTimelinesLength; multiplier++) { - nsecs_t deadline = preferredDeadlineTimestamp + multiplier * frameInterval; + nsecs_t deadlineTimestamp = preferredDeadlineTimestamp + multiplier * frameInterval; // Valid possible frame timelines must have future values. - if (deadline > timestamp) { + if (deadlineTimestamp > timestamp) { if (multiplier == 0) { - setPreferredFrameTimelineIndex(currentIndex); + outVsyncEventData.preferredFrameTimelineIndex = currentIndex; } - nsecs_t expectedVSyncTimestamp = - preferredExpectedVSyncTimestamp + multiplier * frameInterval; - setFrameTimeline(currentIndex, - generateToken(timestamp, deadline, expectedVSyncTimestamp), - expectedVSyncTimestamp, deadline); + nsecs_t expectedPresentationTime = + preferredExpectedPresentationTime + multiplier * frameInterval; + outVsyncEventData.frameTimelines[currentIndex] = + {.vsyncId = + generateToken(timestamp, deadlineTimestamp, expectedPresentationTime), + .deadlineTimestamp = deadlineTimestamp, + .expectedPresentationTime = expectedPresentationTime}; currentIndex++; } } } -void EventThread::generateFrameTimeline(DisplayEventReceiver::Event& event) const { - generateFrameTimeline( - event.vsync.frameInterval, event.header.timestamp, event.vsync.expectedVSyncTimestamp, - event.vsync.deadlineTimestamp, - [&](int index) { event.vsync.preferredFrameTimelineIndex = index; }, - [&](int64_t index, int64_t vsyncId, nsecs_t expectedVSyncTimestamp, - nsecs_t deadlineTimestamp) { - event.vsync.frameTimelines[index] = {.vsyncId = vsyncId, - .deadlineTimestamp = deadlineTimestamp, - .expectedVSyncTimestamp = - expectedVSyncTimestamp}; - }); -} - -void EventThread::generateFrameTimeline(VsyncEventData& out, const nsecs_t frameInterval, - const nsecs_t timestamp) const { - VSyncSource::VSyncData vsyncData; - { - std::lock_guard lock(mMutex); - vsyncData = mVSyncSource->getLatestVSyncData(); - } - generateFrameTimeline( - frameInterval, timestamp, vsyncData.expectedVSyncTimestamp, vsyncData.deadlineTimestamp, - [&](int index) { out.preferredFrameTimelineIndex = index; }, - [&](int64_t index, int64_t vsyncId, nsecs_t expectedVSyncTimestamp, - nsecs_t deadlineTimestamp) { - out.frameTimelines[index] = - VsyncEventData::FrameTimeline(vsyncId, deadlineTimestamp, - expectedVSyncTimestamp); - }); -} - void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, const DisplayEventConsumers& consumers) { for (const auto& consumer : consumers) { DisplayEventReceiver::Event copy = event; if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { - copy.vsync.frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid); - generateFrameTimeline(copy); + const int64_t frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid); + copy.vsync.vsyncData.frameInterval = frameInterval; + generateFrameTimeline(copy.vsync.vsyncData, frameInterval, copy.header.timestamp, + event.vsync.vsyncData.preferredExpectedPresentationTime(), + event.vsync.vsyncData.preferredDeadlineTimestamp()); } switch (consumer->postEvent(copy)) { case NO_ERROR: diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index a858169e65..c406478c17 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -45,6 +45,7 @@ namespace frametimeline { class TokenManager; } // namespace frametimeline +using gui::ParcelableVsyncEventData; using gui::VsyncEventData; // --------------------------------------------------------------------------- @@ -66,7 +67,7 @@ class VSyncSource { public: class VSyncData { public: - nsecs_t expectedVSyncTimestamp; + nsecs_t expectedPresentationTime; nsecs_t deadlineTimestamp; }; @@ -99,7 +100,7 @@ public: binder::Status stealReceiveChannel(gui::BitTube* outChannel) override; binder::Status setVsyncRate(int rate) override; binder::Status requestNextVsync() override; // asynchronous - binder::Status getLatestVsyncEventData(VsyncEventData* outVsyncEventData) override; + binder::Status getLatestVsyncEventData(ParcelableVsyncEventData* outVsyncEventData) override; // Called in response to requestNextVsync. const ResyncCallback resyncCallback; @@ -217,17 +218,10 @@ private: void onVSyncEvent(nsecs_t timestamp, VSyncSource::VSyncData vsyncData) override; int64_t generateToken(nsecs_t timestamp, nsecs_t deadlineTimestamp, - nsecs_t expectedVSyncTimestamp) const; - void generateFrameTimeline(DisplayEventReceiver::Event& event) const; - void generateFrameTimeline(VsyncEventData& out, const nsecs_t frameInterval, - const nsecs_t timestamp) const; - void generateFrameTimeline( - nsecs_t frameInterval, nsecs_t timestamp, nsecs_t preferredExpectedVSyncTimestamp, - nsecs_t preferredDeadlineTimestamp, - std::function setPreferredFrameTimelineIndex, - std::function - setFrameTimeline) const; + nsecs_t expectedPresentationTime) const; + void generateFrameTimeline(VsyncEventData& outVsyncEventData, nsecs_t frameInterval, + nsecs_t timestamp, nsecs_t preferredExpectedPresentationTime, + nsecs_t preferredDeadlineTimestamp) const; const std::unique_ptr mVSyncSource GUARDED_BY(mMutex); frametimeline::TokenManager* const mTokenManager; diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp index a020e2c834..712cd5bdf3 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.cpp +++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp @@ -191,7 +191,8 @@ void MessageQueue::injectorCallback() { for (int i = 0; i < n; i++) { if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { auto& vsync = buffer[i].vsync; - mHandler->dispatchFrame(vsync.vsyncId, vsync.expectedVSyncTimestamp); + mHandler->dispatchFrame(vsync.vsyncData.preferredVsyncId(), + vsync.vsyncData.preferredExpectedPresentationTime()); break; } } diff --git a/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp index 01adbc8962..0e54664f77 100644 --- a/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp +++ b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp @@ -28,23 +28,24 @@ public: TEST_F(DisplayEventReceiverTest, getLatestVsyncEventData) { const nsecs_t now = systemTime(); - VsyncEventData vsyncEventData; - EXPECT_EQ(NO_ERROR, mDisplayEventReceiver.getLatestVsyncEventData(&vsyncEventData)); + ParcelableVsyncEventData parcelableVsyncEventData; + EXPECT_EQ(NO_ERROR, mDisplayEventReceiver.getLatestVsyncEventData(&parcelableVsyncEventData)); + const VsyncEventData& vsyncEventData = parcelableVsyncEventData.vsync; EXPECT_NE(std::numeric_limits::max(), vsyncEventData.preferredFrameTimelineIndex); EXPECT_GT(vsyncEventData.frameTimelines[0].deadlineTimestamp, now) << "Deadline timestamp should be greater than frame time"; - for (size_t i = 0; i < vsyncEventData.frameTimelines.size(); i++) { - EXPECT_NE(FrameTimelineInfo::INVALID_VSYNC_ID, vsyncEventData.frameTimelines[i].id); - EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime, + for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { + EXPECT_NE(FrameTimelineInfo::INVALID_VSYNC_ID, vsyncEventData.frameTimelines[i].vsyncId); + EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime, vsyncEventData.frameTimelines[i].deadlineTimestamp) << "Expected vsync timestamp should be greater than deadline"; if (i > 0) { EXPECT_GT(vsyncEventData.frameTimelines[i].deadlineTimestamp, vsyncEventData.frameTimelines[i - 1].deadlineTimestamp) << "Deadline timestamp out of order for frame timeline " << i; - EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime, - vsyncEventData.frameTimelines[i - 1].expectedPresentTime) + EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime, + vsyncEventData.frameTimelines[i - 1].expectedPresentationTime) << "Expected vsync timestamp out of order for frame timeline " << i; } } diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp index 5c16feeda8..8a2305b365 100644 --- a/services/surfaceflinger/tests/LayerCallback_test.cpp +++ b/services/surfaceflinger/tests/LayerCallback_test.cpp @@ -141,11 +141,12 @@ public: continue; } - vsync = {event.vsync.vsyncId, event.vsync.expectedVSyncTimestamp}; + vsync = {event.vsync.vsyncData.preferredVsyncId(), + event.vsync.vsyncData.preferredExpectedPresentationTime()}; } EXPECT_GE(vsync.vsyncId, 1); - EXPECT_GT(event.vsync.expectedVSyncTimestamp, systemTime()); + EXPECT_GT(vsync.expectedPresentTime, systemTime()); return vsync; } diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp index 0b6b475222..ec27edac6e 100644 --- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp +++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp @@ -229,7 +229,7 @@ TEST_F(DispSyncSourceTest, waitForCallbacks) { ASSERT_TRUE(callbackData.has_value()); const auto [when, vsyncData] = callbackData.value(); EXPECT_EQ(when, - vsyncData.expectedVSyncTimestamp - mWorkDuration.count() - + vsyncData.expectedPresentationTime - mWorkDuration.count() - mReadyDuration.count()); } } @@ -261,7 +261,7 @@ TEST_F(DispSyncSourceTest, waitForCallbacksWithDurationChange) { ASSERT_TRUE(callbackData.has_value()); const auto [when, vsyncData] = callbackData.value(); EXPECT_EQ(when, - vsyncData.expectedVSyncTimestamp - mWorkDuration.count() - + vsyncData.expectedPresentationTime - mWorkDuration.count() - mReadyDuration.count()); } @@ -283,7 +283,7 @@ TEST_F(DispSyncSourceTest, waitForCallbacksWithDurationChange) { const auto callbackData = mVSyncEventCallRecorder.waitForCall(); ASSERT_TRUE(callbackData.has_value()); const auto [when, vsyncData] = callbackData.value(); - EXPECT_EQ(when, vsyncData.expectedVSyncTimestamp - newDuration.count()); + EXPECT_EQ(when, vsyncData.expectedPresentationTime - newDuration.count()); } EXPECT_CALL(*mVSyncDispatch, cancel(_)).Times(1); @@ -307,9 +307,9 @@ TEST_F(DispSyncSourceTest, getLatestVsyncData) { const auto vsyncData = mDispSyncSource->getLatestVSyncData(); ASSERT_GT(vsyncData.deadlineTimestamp, now); - ASSERT_GT(vsyncData.expectedVSyncTimestamp, vsyncData.deadlineTimestamp); + ASSERT_GT(vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp); EXPECT_EQ(vsyncData.deadlineTimestamp, - vsyncData.expectedVSyncTimestamp - vsyncInternalDuration); + vsyncData.expectedPresentationTime - vsyncInternalDuration); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index cc0a40f74b..14d8f987b0 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -99,7 +99,7 @@ protected: nsecs_t expectedTimestamp, unsigned expectedCount); void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount); void expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp, - nsecs_t preferredDeadline); + VSyncSource::VSyncData preferredVsyncData); void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, bool expectedConnected); void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, @@ -252,40 +252,42 @@ void EventThreadTest::expectVsyncEventReceivedByConnection(nsecs_t expectedTimes expectedCount); } -void EventThreadTest::expectVsyncEventFrameTimelinesCorrect(nsecs_t expectedTimestamp, - nsecs_t preferredDeadline) { +void EventThreadTest::expectVsyncEventFrameTimelinesCorrect( + nsecs_t expectedTimestamp, VSyncSource::VSyncData preferredVsyncData) { auto args = mConnectionEventCallRecorder.waitForCall(); ASSERT_TRUE(args.has_value()) << " did not receive an event for timestamp " << expectedTimestamp; const auto& event = std::get<0>(args.value()); for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { - auto prediction = - mTokenManager->getPredictionsForToken(event.vsync.frameTimelines[i].vsyncId); + auto prediction = mTokenManager->getPredictionsForToken( + event.vsync.vsyncData.frameTimelines[i].vsyncId); EXPECT_TRUE(prediction.has_value()); - EXPECT_EQ(prediction.value().endTime, event.vsync.frameTimelines[i].deadlineTimestamp) + EXPECT_EQ(prediction.value().endTime, + event.vsync.vsyncData.frameTimelines[i].deadlineTimestamp) << "Deadline timestamp does not match cached value"; EXPECT_EQ(prediction.value().presentTime, - event.vsync.frameTimelines[i].expectedVSyncTimestamp) - << "Expected vsync timestamp does not match cached value"; + event.vsync.vsyncData.frameTimelines[i].expectedPresentationTime) + << "Expected vsync.vsyncData timestamp does not match cached value"; if (i > 0) { - EXPECT_GT(event.vsync.frameTimelines[i].deadlineTimestamp, - event.vsync.frameTimelines[i - 1].deadlineTimestamp) + EXPECT_GT(event.vsync.vsyncData.frameTimelines[i].deadlineTimestamp, + event.vsync.vsyncData.frameTimelines[i - 1].deadlineTimestamp) << "Deadline timestamp out of order for frame timeline " << i; - EXPECT_GT(event.vsync.frameTimelines[i].expectedVSyncTimestamp, - event.vsync.frameTimelines[i - 1].expectedVSyncTimestamp) - << "Expected vsync timestamp out of order for frame timeline " << i; + EXPECT_GT(event.vsync.vsyncData.frameTimelines[i].expectedPresentationTime, + event.vsync.vsyncData.frameTimelines[i - 1].expectedPresentationTime) + << "Expected vsync.vsyncData timestamp out of order for frame timeline " << i; } // Vsync ID order lines up with registration into test token manager. - EXPECT_EQ(i, event.vsync.frameTimelines[i].vsyncId) + EXPECT_EQ(i, event.vsync.vsyncData.frameTimelines[i].vsyncId) << "Vsync ID incorrect for frame timeline " << i; - if (i == event.vsync.preferredFrameTimelineIndex) { - EXPECT_EQ(event.vsync.frameTimelines[i].deadlineTimestamp, preferredDeadline) + if (i == event.vsync.vsyncData.preferredFrameTimelineIndex) { + EXPECT_EQ(event.vsync.vsyncData.frameTimelines[i].deadlineTimestamp, + preferredVsyncData.deadlineTimestamp) << "Preferred deadline timestamp incorrect" << i; - EXPECT_EQ(event.vsync.frameTimelines[i].expectedVSyncTimestamp, - event.vsync.expectedVSyncTimestamp) - << "Preferred expected vsync timestamp incorrect" << i; + EXPECT_EQ(event.vsync.vsyncData.frameTimelines[i].expectedPresentationTime, + preferredVsyncData.expectedPresentationTime) + << "Preferred expected vsync.vsyncData timestamp incorrect" << i; } } } @@ -397,16 +399,17 @@ TEST_F(EventThreadTest, requestNextVsyncEventFrameTimelinesCorrect) { // Use the received callback to signal a vsync event. // The interceptor should receive the event, as well as the connection. - mCallback->onVSyncEvent(123, {456, 789}); + VSyncSource::VSyncData vsyncData = {456, 789}; + mCallback->onVSyncEvent(123, vsyncData); expectInterceptCallReceived(123); - expectVsyncEventFrameTimelinesCorrect(123, 789); + expectVsyncEventFrameTimelinesCorrect(123, vsyncData); } TEST_F(EventThreadTest, getLatestVsyncEventData) { const nsecs_t now = systemTime(); const nsecs_t preferredDeadline = now + 10000000; - const nsecs_t preferredExpectedVSyncTimestamp = now + 20000000; - const VSyncSource::VSyncData preferredData = {preferredExpectedVSyncTimestamp, + const nsecs_t preferredExpectedPresentationTime = now + 20000000; + const VSyncSource::VSyncData preferredData = {preferredExpectedPresentationTime, preferredDeadline}; EXPECT_CALL(*mVSyncSource, getLatestVSyncData()).WillOnce(Return(preferredData)); @@ -415,14 +418,14 @@ TEST_F(EventThreadTest, getLatestVsyncEventData) { << "Deadline timestamp should be greater than frame time"; for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { auto prediction = - mTokenManager->getPredictionsForToken(vsyncEventData.frameTimelines[i].id); + mTokenManager->getPredictionsForToken(vsyncEventData.frameTimelines[i].vsyncId); EXPECT_TRUE(prediction.has_value()); EXPECT_EQ(prediction.value().endTime, vsyncEventData.frameTimelines[i].deadlineTimestamp) << "Deadline timestamp does not match cached value"; EXPECT_EQ(prediction.value().presentTime, - vsyncEventData.frameTimelines[i].expectedPresentTime) + vsyncEventData.frameTimelines[i].expectedPresentationTime) << "Expected vsync timestamp does not match cached value"; - EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime, + EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime, vsyncEventData.frameTimelines[i].deadlineTimestamp) << "Expected vsync timestamp should be greater than deadline"; @@ -430,19 +433,19 @@ TEST_F(EventThreadTest, getLatestVsyncEventData) { EXPECT_GT(vsyncEventData.frameTimelines[i].deadlineTimestamp, vsyncEventData.frameTimelines[i - 1].deadlineTimestamp) << "Deadline timestamp out of order for frame timeline " << i; - EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentTime, - vsyncEventData.frameTimelines[i - 1].expectedPresentTime) + EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime, + vsyncEventData.frameTimelines[i - 1].expectedPresentationTime) << "Expected vsync timestamp out of order for frame timeline " << i; } // Vsync ID order lines up with registration into test token manager. - EXPECT_EQ(i, vsyncEventData.frameTimelines[i].id) + EXPECT_EQ(i, vsyncEventData.frameTimelines[i].vsyncId) << "Vsync ID incorrect for frame timeline " << i; if (i == vsyncEventData.preferredFrameTimelineIndex) { EXPECT_EQ(vsyncEventData.frameTimelines[i].deadlineTimestamp, preferredDeadline) << "Preferred deadline timestamp incorrect" << i; - EXPECT_EQ(vsyncEventData.frameTimelines[i].expectedPresentTime, - preferredExpectedVSyncTimestamp) + EXPECT_EQ(vsyncEventData.frameTimelines[i].expectedPresentationTime, + preferredExpectedPresentationTime) << "Preferred expected vsync timestamp incorrect" << i; } } -- cgit v1.2.3-59-g8ed1b From 4cf8bab5f31611c4eb733cf2a51024449541cb80 Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Mon, 14 Mar 2022 14:38:45 -0700 Subject: Add JNI getLatestVsyncEventData. Bug: 205721584 Test: atest ChoreographerTest Change-Id: I005fbffdf0db47e6cb636b22a0a316d18f5bbb90 --- libs/gui/DisplayEventDispatcher.cpp | 5 +++++ libs/gui/include/gui/DisplayEventDispatcher.h | 1 + 2 files changed, 6 insertions(+) (limited to 'libs/gui/DisplayEventDispatcher.cpp') diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index 39d380d9e1..dfdce20438 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -197,4 +197,9 @@ bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, return gotVsync; } +status_t DisplayEventDispatcher::getLatestVsyncEventData( + ParcelableVsyncEventData* outVsyncEventData) const { + return mReceiver.getLatestVsyncEventData(outVsyncEventData); +} + } // namespace android diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index 71968fa59f..a3425395bf 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -34,6 +34,7 @@ public: void injectEvent(const DisplayEventReceiver::Event& event); int getFd() const; virtual int handleEvent(int receiveFd, int events, void* data); + status_t getLatestVsyncEventData(ParcelableVsyncEventData* outVsyncEventData) const; protected: virtual ~DisplayEventDispatcher() = default; -- cgit v1.2.3-59-g8ed1b