Loading services/surfaceflinger/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -174,6 +174,7 @@ filegroup { "Scheduler/VSyncDispatchTimerQueue.cpp", "Scheduler/VSyncPredictor.cpp", "Scheduler/VSyncModulator.cpp", "Scheduler/VSyncReactor.cpp", "StartPropertySetThread.cpp", "SurfaceFlinger.cpp", "SurfaceFlingerDefaultFactory.cpp", Loading services/surfaceflinger/Scheduler/VSyncReactor.cpp 0 → 100644 +76 −0 Original line number Diff line number Diff line /* * Copyright 2019 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 "VSyncReactor.h" #include "VSyncDispatch.h" #include "VSyncTracker.h" namespace android::scheduler { VSyncReactor::VSyncReactor(std::unique_ptr<VSyncDispatch> dispatch, std::unique_ptr<VSyncTracker> tracker, size_t pendingFenceLimit) : mDispatch(std::move(dispatch)), mTracker(std::move(tracker)), mPendingLimit(pendingFenceLimit) {} bool VSyncReactor::addPresentFence(const std::shared_ptr<FenceTime>& fence) { if (!fence) { return false; } nsecs_t const signalTime = fence->getCachedSignalTime(); if (signalTime == Fence::SIGNAL_TIME_INVALID) { return true; } std::lock_guard<std::mutex> lk(mMutex); if (mIgnorePresentFences) { return true; } for (auto it = mUnfiredFences.begin(); it != mUnfiredFences.end();) { auto const time = (*it)->getCachedSignalTime(); if (time == Fence::SIGNAL_TIME_PENDING) { it++; } else if (time == Fence::SIGNAL_TIME_INVALID) { it = mUnfiredFences.erase(it); } else { mTracker->addVsyncTimestamp(time); it = mUnfiredFences.erase(it); } } if (signalTime == Fence::SIGNAL_TIME_PENDING) { if (mPendingLimit == mUnfiredFences.size()) { mUnfiredFences.erase(mUnfiredFences.begin()); } mUnfiredFences.push_back(fence); } else { mTracker->addVsyncTimestamp(signalTime); } return false; // TODO(b/144707443): add policy for turning on HWVsync. } void VSyncReactor::setIgnorePresentFences(bool ignoration) { std::lock_guard<std::mutex> lk(mMutex); mIgnorePresentFences = ignoration; if (mIgnorePresentFences == true) { mUnfiredFences.clear(); } } } // namespace android::scheduler services/surfaceflinger/Scheduler/VSyncReactor.h 0 → 100644 +49 −0 Original line number Diff line number Diff line /* * Copyright 2019 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 <android-base/thread_annotations.h> #include <ui/FenceTime.h> #include <memory> #include <mutex> #include <vector> namespace android::scheduler { class VSyncDispatch; class VSyncTracker; // TODO (b/145217110): consider renaming. class VSyncReactor /* TODO (b/140201379): : public android::DispSync */ { public: VSyncReactor(std::unique_ptr<VSyncDispatch> dispatch, std::unique_ptr<VSyncTracker> tracker, size_t pendingFenceLimit); bool addPresentFence(const std::shared_ptr<FenceTime>& fence); void setIgnorePresentFences(bool ignoration); private: std::unique_ptr<VSyncDispatch> const mDispatch; std::unique_ptr<VSyncTracker> const mTracker; size_t const mPendingLimit; std::mutex mMutex; bool mIgnorePresentFences GUARDED_BY(mMutex) = false; std::vector<std::shared_ptr<FenceTime>> mUnfiredFences GUARDED_BY(mMutex); }; } // namespace android::scheduler services/surfaceflinger/tests/unittests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ cc_test { "VSyncDispatchTimerQueueTest.cpp", "VSyncDispatchRealtimeTest.cpp", "VSyncPredictorTest.cpp", "VSyncReactorTest.cpp", "mock/DisplayHardware/MockComposer.cpp", "mock/DisplayHardware/MockDisplay.cpp", "mock/DisplayHardware/MockPowerAdvisor.cpp", Loading services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp 0 → 100644 +184 −0 Original line number Diff line number Diff line /* * Copyright 2019 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. */ #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" #define LOG_NDEBUG 0 #include "Scheduler/VSyncDispatch.h" #include "Scheduler/VSyncReactor.h" #include "Scheduler/VSyncTracker.h" #include <gmock/gmock.h> #include <gtest/gtest.h> #include <ui/Fence.h> #include <ui/FenceTime.h> #include <array> using namespace testing; using namespace std::literals; namespace android::scheduler { class MockVSyncTracker : public VSyncTracker { public: MOCK_METHOD1(addVsyncTimestamp, void(nsecs_t)); MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t)); }; class VSyncTrackerWrapper : public VSyncTracker { public: VSyncTrackerWrapper(std::shared_ptr<VSyncTracker> const& tracker) : mTracker(tracker) {} void addVsyncTimestamp(nsecs_t timestamp) final { mTracker->addVsyncTimestamp(timestamp); } nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final { return mTracker->nextAnticipatedVSyncTimeFrom(timePoint); } private: std::shared_ptr<VSyncTracker> const mTracker; }; class MockVSyncDispatch : public VSyncDispatch { public: MOCK_METHOD2(registerCallback, CallbackToken(std::function<void(nsecs_t)> const&, std::string)); MOCK_METHOD1(unregisterCallback, void(CallbackToken)); MOCK_METHOD3(schedule, ScheduleResult(CallbackToken, nsecs_t, nsecs_t)); MOCK_METHOD1(cancel, CancelResult(CallbackToken token)); }; class VSyncDispatchWrapper : public VSyncDispatch { public: VSyncDispatchWrapper(std::shared_ptr<VSyncDispatch> const& dispatch) : mDispatch(dispatch) {} CallbackToken registerCallback(std::function<void(nsecs_t)> const& callbackFn, std::string callbackName) final { return mDispatch->registerCallback(callbackFn, callbackName); } void unregisterCallback(CallbackToken token) final { mDispatch->unregisterCallback(token); } ScheduleResult schedule(CallbackToken token, nsecs_t workDuration, nsecs_t earliestVsync) final { return mDispatch->schedule(token, workDuration, earliestVsync); } CancelResult cancel(CallbackToken token) final { return mDispatch->cancel(token); } private: std::shared_ptr<VSyncDispatch> const mDispatch; }; std::shared_ptr<FenceTime> generateInvalidFence() { sp<Fence> fence = new Fence(); return std::make_shared<FenceTime>(fence); } std::shared_ptr<FenceTime> generatePendingFence() { sp<Fence> fence = new Fence(dup(fileno(tmpfile()))); return std::make_shared<FenceTime>(fence); } void signalFenceWithTime(std::shared_ptr<FenceTime> const& fence, nsecs_t time) { FenceTime::Snapshot snap(time); fence->applyTrustedSnapshot(snap); } std::shared_ptr<FenceTime> generateSignalledFenceWithTime(nsecs_t time) { sp<Fence> fence = new Fence(dup(fileno(tmpfile()))); std::shared_ptr<FenceTime> ft = std::make_shared<FenceTime>(fence); signalFenceWithTime(ft, time); return ft; } class VSyncReactorTest : public testing::Test { protected: VSyncReactorTest() : mMockDispatch(std::make_shared<MockVSyncDispatch>()), mMockTracker(std::make_shared<MockVSyncTracker>()), mReactor(std::make_unique<VSyncDispatchWrapper>(mMockDispatch), std::make_unique<VSyncTrackerWrapper>(mMockTracker), kPendingLimit) {} std::shared_ptr<MockVSyncDispatch> mMockDispatch; std::shared_ptr<MockVSyncTracker> mMockTracker; static constexpr size_t kPendingLimit = 3; static constexpr nsecs_t dummyTime = 47; VSyncReactor mReactor; }; TEST_F(VSyncReactorTest, addingNullFenceCheck) { EXPECT_FALSE(mReactor.addPresentFence(nullptr)); } TEST_F(VSyncReactorTest, addingInvalidFenceSignalsNeedsMoreInfo) { EXPECT_TRUE(mReactor.addPresentFence(generateInvalidFence())); } TEST_F(VSyncReactorTest, addingSignalledFenceAddsToTracker) { EXPECT_CALL(*mMockTracker, addVsyncTimestamp(dummyTime)); EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(dummyTime))); } TEST_F(VSyncReactorTest, addingPendingFenceAddsSignalled) { nsecs_t anotherDummyTime = 2919019201; EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(0); auto pendingFence = generatePendingFence(); EXPECT_FALSE(mReactor.addPresentFence(pendingFence)); Mock::VerifyAndClearExpectations(mMockTracker.get()); signalFenceWithTime(pendingFence, dummyTime); EXPECT_CALL(*mMockTracker, addVsyncTimestamp(dummyTime)); EXPECT_CALL(*mMockTracker, addVsyncTimestamp(anotherDummyTime)); EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(anotherDummyTime))); } TEST_F(VSyncReactorTest, limitsPendingFences) { std::array<std::shared_ptr<FenceTime>, kPendingLimit * 2> fences; std::array<nsecs_t, fences.size()> fakeTimes; std::generate(fences.begin(), fences.end(), [] { return generatePendingFence(); }); std::generate(fakeTimes.begin(), fakeTimes.end(), [i = 10]() mutable { i++; return i * i; }); for (auto const& fence : fences) { mReactor.addPresentFence(fence); } for (auto i = fences.size() - kPendingLimit; i < fences.size(); i++) { EXPECT_CALL(*mMockTracker, addVsyncTimestamp(fakeTimes[i])); } for (auto i = 0u; i < fences.size(); i++) { signalFenceWithTime(fences[i], fakeTimes[i]); } mReactor.addPresentFence(generatePendingFence()); } TEST_F(VSyncReactorTest, ignoresPresentFencesWhenToldTo) { static constexpr size_t aFewTimes = 8; EXPECT_CALL(*mMockTracker, addVsyncTimestamp(dummyTime)).Times(1); mReactor.setIgnorePresentFences(true); for (auto i = 0; i < aFewTimes; i++) { mReactor.addPresentFence(generateSignalledFenceWithTime(dummyTime)); } mReactor.setIgnorePresentFences(false); EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(dummyTime))); } } // namespace android::scheduler Loading
services/surfaceflinger/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -174,6 +174,7 @@ filegroup { "Scheduler/VSyncDispatchTimerQueue.cpp", "Scheduler/VSyncPredictor.cpp", "Scheduler/VSyncModulator.cpp", "Scheduler/VSyncReactor.cpp", "StartPropertySetThread.cpp", "SurfaceFlinger.cpp", "SurfaceFlingerDefaultFactory.cpp", Loading
services/surfaceflinger/Scheduler/VSyncReactor.cpp 0 → 100644 +76 −0 Original line number Diff line number Diff line /* * Copyright 2019 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 "VSyncReactor.h" #include "VSyncDispatch.h" #include "VSyncTracker.h" namespace android::scheduler { VSyncReactor::VSyncReactor(std::unique_ptr<VSyncDispatch> dispatch, std::unique_ptr<VSyncTracker> tracker, size_t pendingFenceLimit) : mDispatch(std::move(dispatch)), mTracker(std::move(tracker)), mPendingLimit(pendingFenceLimit) {} bool VSyncReactor::addPresentFence(const std::shared_ptr<FenceTime>& fence) { if (!fence) { return false; } nsecs_t const signalTime = fence->getCachedSignalTime(); if (signalTime == Fence::SIGNAL_TIME_INVALID) { return true; } std::lock_guard<std::mutex> lk(mMutex); if (mIgnorePresentFences) { return true; } for (auto it = mUnfiredFences.begin(); it != mUnfiredFences.end();) { auto const time = (*it)->getCachedSignalTime(); if (time == Fence::SIGNAL_TIME_PENDING) { it++; } else if (time == Fence::SIGNAL_TIME_INVALID) { it = mUnfiredFences.erase(it); } else { mTracker->addVsyncTimestamp(time); it = mUnfiredFences.erase(it); } } if (signalTime == Fence::SIGNAL_TIME_PENDING) { if (mPendingLimit == mUnfiredFences.size()) { mUnfiredFences.erase(mUnfiredFences.begin()); } mUnfiredFences.push_back(fence); } else { mTracker->addVsyncTimestamp(signalTime); } return false; // TODO(b/144707443): add policy for turning on HWVsync. } void VSyncReactor::setIgnorePresentFences(bool ignoration) { std::lock_guard<std::mutex> lk(mMutex); mIgnorePresentFences = ignoration; if (mIgnorePresentFences == true) { mUnfiredFences.clear(); } } } // namespace android::scheduler
services/surfaceflinger/Scheduler/VSyncReactor.h 0 → 100644 +49 −0 Original line number Diff line number Diff line /* * Copyright 2019 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 <android-base/thread_annotations.h> #include <ui/FenceTime.h> #include <memory> #include <mutex> #include <vector> namespace android::scheduler { class VSyncDispatch; class VSyncTracker; // TODO (b/145217110): consider renaming. class VSyncReactor /* TODO (b/140201379): : public android::DispSync */ { public: VSyncReactor(std::unique_ptr<VSyncDispatch> dispatch, std::unique_ptr<VSyncTracker> tracker, size_t pendingFenceLimit); bool addPresentFence(const std::shared_ptr<FenceTime>& fence); void setIgnorePresentFences(bool ignoration); private: std::unique_ptr<VSyncDispatch> const mDispatch; std::unique_ptr<VSyncTracker> const mTracker; size_t const mPendingLimit; std::mutex mMutex; bool mIgnorePresentFences GUARDED_BY(mMutex) = false; std::vector<std::shared_ptr<FenceTime>> mUnfiredFences GUARDED_BY(mMutex); }; } // namespace android::scheduler
services/surfaceflinger/tests/unittests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ cc_test { "VSyncDispatchTimerQueueTest.cpp", "VSyncDispatchRealtimeTest.cpp", "VSyncPredictorTest.cpp", "VSyncReactorTest.cpp", "mock/DisplayHardware/MockComposer.cpp", "mock/DisplayHardware/MockDisplay.cpp", "mock/DisplayHardware/MockPowerAdvisor.cpp", Loading
services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp 0 → 100644 +184 −0 Original line number Diff line number Diff line /* * Copyright 2019 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. */ #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" #define LOG_NDEBUG 0 #include "Scheduler/VSyncDispatch.h" #include "Scheduler/VSyncReactor.h" #include "Scheduler/VSyncTracker.h" #include <gmock/gmock.h> #include <gtest/gtest.h> #include <ui/Fence.h> #include <ui/FenceTime.h> #include <array> using namespace testing; using namespace std::literals; namespace android::scheduler { class MockVSyncTracker : public VSyncTracker { public: MOCK_METHOD1(addVsyncTimestamp, void(nsecs_t)); MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t)); }; class VSyncTrackerWrapper : public VSyncTracker { public: VSyncTrackerWrapper(std::shared_ptr<VSyncTracker> const& tracker) : mTracker(tracker) {} void addVsyncTimestamp(nsecs_t timestamp) final { mTracker->addVsyncTimestamp(timestamp); } nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final { return mTracker->nextAnticipatedVSyncTimeFrom(timePoint); } private: std::shared_ptr<VSyncTracker> const mTracker; }; class MockVSyncDispatch : public VSyncDispatch { public: MOCK_METHOD2(registerCallback, CallbackToken(std::function<void(nsecs_t)> const&, std::string)); MOCK_METHOD1(unregisterCallback, void(CallbackToken)); MOCK_METHOD3(schedule, ScheduleResult(CallbackToken, nsecs_t, nsecs_t)); MOCK_METHOD1(cancel, CancelResult(CallbackToken token)); }; class VSyncDispatchWrapper : public VSyncDispatch { public: VSyncDispatchWrapper(std::shared_ptr<VSyncDispatch> const& dispatch) : mDispatch(dispatch) {} CallbackToken registerCallback(std::function<void(nsecs_t)> const& callbackFn, std::string callbackName) final { return mDispatch->registerCallback(callbackFn, callbackName); } void unregisterCallback(CallbackToken token) final { mDispatch->unregisterCallback(token); } ScheduleResult schedule(CallbackToken token, nsecs_t workDuration, nsecs_t earliestVsync) final { return mDispatch->schedule(token, workDuration, earliestVsync); } CancelResult cancel(CallbackToken token) final { return mDispatch->cancel(token); } private: std::shared_ptr<VSyncDispatch> const mDispatch; }; std::shared_ptr<FenceTime> generateInvalidFence() { sp<Fence> fence = new Fence(); return std::make_shared<FenceTime>(fence); } std::shared_ptr<FenceTime> generatePendingFence() { sp<Fence> fence = new Fence(dup(fileno(tmpfile()))); return std::make_shared<FenceTime>(fence); } void signalFenceWithTime(std::shared_ptr<FenceTime> const& fence, nsecs_t time) { FenceTime::Snapshot snap(time); fence->applyTrustedSnapshot(snap); } std::shared_ptr<FenceTime> generateSignalledFenceWithTime(nsecs_t time) { sp<Fence> fence = new Fence(dup(fileno(tmpfile()))); std::shared_ptr<FenceTime> ft = std::make_shared<FenceTime>(fence); signalFenceWithTime(ft, time); return ft; } class VSyncReactorTest : public testing::Test { protected: VSyncReactorTest() : mMockDispatch(std::make_shared<MockVSyncDispatch>()), mMockTracker(std::make_shared<MockVSyncTracker>()), mReactor(std::make_unique<VSyncDispatchWrapper>(mMockDispatch), std::make_unique<VSyncTrackerWrapper>(mMockTracker), kPendingLimit) {} std::shared_ptr<MockVSyncDispatch> mMockDispatch; std::shared_ptr<MockVSyncTracker> mMockTracker; static constexpr size_t kPendingLimit = 3; static constexpr nsecs_t dummyTime = 47; VSyncReactor mReactor; }; TEST_F(VSyncReactorTest, addingNullFenceCheck) { EXPECT_FALSE(mReactor.addPresentFence(nullptr)); } TEST_F(VSyncReactorTest, addingInvalidFenceSignalsNeedsMoreInfo) { EXPECT_TRUE(mReactor.addPresentFence(generateInvalidFence())); } TEST_F(VSyncReactorTest, addingSignalledFenceAddsToTracker) { EXPECT_CALL(*mMockTracker, addVsyncTimestamp(dummyTime)); EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(dummyTime))); } TEST_F(VSyncReactorTest, addingPendingFenceAddsSignalled) { nsecs_t anotherDummyTime = 2919019201; EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(0); auto pendingFence = generatePendingFence(); EXPECT_FALSE(mReactor.addPresentFence(pendingFence)); Mock::VerifyAndClearExpectations(mMockTracker.get()); signalFenceWithTime(pendingFence, dummyTime); EXPECT_CALL(*mMockTracker, addVsyncTimestamp(dummyTime)); EXPECT_CALL(*mMockTracker, addVsyncTimestamp(anotherDummyTime)); EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(anotherDummyTime))); } TEST_F(VSyncReactorTest, limitsPendingFences) { std::array<std::shared_ptr<FenceTime>, kPendingLimit * 2> fences; std::array<nsecs_t, fences.size()> fakeTimes; std::generate(fences.begin(), fences.end(), [] { return generatePendingFence(); }); std::generate(fakeTimes.begin(), fakeTimes.end(), [i = 10]() mutable { i++; return i * i; }); for (auto const& fence : fences) { mReactor.addPresentFence(fence); } for (auto i = fences.size() - kPendingLimit; i < fences.size(); i++) { EXPECT_CALL(*mMockTracker, addVsyncTimestamp(fakeTimes[i])); } for (auto i = 0u; i < fences.size(); i++) { signalFenceWithTime(fences[i], fakeTimes[i]); } mReactor.addPresentFence(generatePendingFence()); } TEST_F(VSyncReactorTest, ignoresPresentFencesWhenToldTo) { static constexpr size_t aFewTimes = 8; EXPECT_CALL(*mMockTracker, addVsyncTimestamp(dummyTime)).Times(1); mReactor.setIgnorePresentFences(true); for (auto i = 0; i < aFewTimes; i++) { mReactor.addPresentFence(generateSignalledFenceWithTime(dummyTime)); } mReactor.setIgnorePresentFences(false); EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(dummyTime))); } } // namespace android::scheduler