diff options
author | 2021-11-04 19:32:24 +0000 | |
---|---|---|
committer | 2021-11-04 12:44:59 -0700 | |
commit | 3f0286607e9d35196fdff27f84381dffb7bafcad (patch) | |
tree | 13a1516759c73f6be74d56edc1d42dac04e9c7e0 | |
parent | 4488087777617032701d63495b2238aaf36b5eae (diff) |
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
-rw-r--r-- | libs/gui/DisplayEventDispatcher.cpp | 16 | ||||
-rw-r--r-- | libs/gui/include/gui/DisplayEventDispatcher.h | 24 | ||||
-rw-r--r-- | libs/gui/include/gui/DisplayEventReceiver.h | 9 | ||||
-rw-r--r-- | libs/nativedisplay/AChoreographer.cpp | 34 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/EventThread.cpp | 45 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/EventThread.h | 4 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/EventThreadTest.cpp | 51 |
7 files changed, 150 insertions, 33 deletions
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 <gui/DisplayEventReceiver.h> #include <utils/Log.h> #include <utils/Looper.h> +#include <array> 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<int64_t>::max(); + + // The anticipated Vsync present time. + int64_t expectedPresentTime = 0; + }; + + // Sorted possible frame timelines. + std::array<FrameTimeline, DisplayEventReceiver::kFrameTimelinesLength> frameTimelines; + + // Index into the frameTimelines that represents the platform's preferred frame timeline. + size_t preferredFrameTimelineIndex = std::numeric_limits<size_t>::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<FrameTimeline> frameTimelines; + std::array<VsyncEventData::FrameTimeline, DisplayEventReceiver::kFrameTimelinesLength> + frameTimelines; size_t preferredFrameTimelineIndex; @@ -456,14 +449,9 @@ bool Choreographer::inCallback() const { } ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const { - std::vector<ChoreographerFrameCallbackDataImpl::FrameTimeline> 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<std::mutex> 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<VSyncSource> 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<impl::EventThread> mThread; sp<MockEventThreadConnection> mConnection; sp<MockEventThreadConnection> mThrottledConnection; + std::unique_ptr<frametimeline::impl::TokenManager> mTokenManager; static constexpr uid_t mConnectionUid = 443; static constexpr uid_t mThrottledConnectionUid = 177; @@ -173,8 +177,8 @@ void EventThreadTest::createThread(std::unique_ptr<VSyncSource> source) { return VSYNC_PERIOD.count(); }; - mThread = std::make_unique<impl::EventThread>(std::move(source), - /*tokenManager=*/nullptr, + mTokenManager = std::make_unique<frametimeline::impl::TokenManager>(); + mThread = std::make_unique<impl::EventThread>(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}; |