diff options
author | 2019-01-12 05:36:09 +0000 | |
---|---|---|
committer | 2019-01-12 05:36:09 +0000 | |
commit | e3dbb294940461cad6a04625501b93d3daf6fb0f (patch) | |
tree | 304e83611657a54a81449dfe656987c9431292dd | |
parent | 65047e1ab2899cd2b349345a248a4550202e92a3 (diff) | |
parent | 7d1d68309356cd676100fdd4915aaffac1f36180 (diff) |
Merge "SF: Adding callback to Scheduler for setting refresh rate to 60 and 90."
-rw-r--r-- | services/surfaceflinger/Scheduler/EventThread.cpp | 17 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/EventThread.h | 13 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/MessageQueue.cpp | 4 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/MessageQueue.h | 4 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/Scheduler.cpp | 30 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/Scheduler.h | 11 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 114 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 10 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/EventThreadTest.cpp | 2 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/mock/MockEventThread.h | 2 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h | 1 |
11 files changed, 166 insertions, 42 deletions
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 1683982485..bf925b2add 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -67,7 +67,13 @@ status_t EventThreadConnection::setVsyncRate(uint32_t count) { } void EventThreadConnection::requestNextVsync() { - mEventThread->requestNextVsync(this); + ATRACE_NAME("requestNextVsync"); + mEventThread->requestNextVsync(this, true); +} + +void EventThreadConnection::requestNextVsyncForHWC() { + ATRACE_NAME("requestNextVsyncForHWC"); + mEventThread->requestNextVsync(this, false); } status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) { @@ -184,16 +190,17 @@ void EventThread::setVsyncRate(uint32_t count, const sp<EventThreadConnection>& } } -void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) { - std::lock_guard<std::mutex> lock(mMutex); - if (mResetIdleTimer) { +void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection, bool reset) { + if (mResetIdleTimer && reset) { + ATRACE_NAME("resetIdleTimer"); mResetIdleTimer(); } - if (mResyncWithRateLimitCallback) { mResyncWithRateLimitCallback(); } + std::lock_guard<std::mutex> lock(mMutex); + if (connection->count < 0) { connection->count = 0; mCondition.notify_all(); diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 66f54bddd0..e11048845e 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -68,6 +68,9 @@ public: status_t stealReceiveChannel(gui::BitTube* outChannel) override; status_t setVsyncRate(uint32_t count) override; void requestNextVsync() override; // asynchronous + // Requesting Vsync for HWC does not reset the idle timer, since HWC requires a refresh + // in order to update the configs. + void requestNextVsyncForHWC(); // count >= 1 : continuous event. count is the vsync rate // count == 0 : one-shot event that has not fired @@ -105,7 +108,9 @@ public: virtual status_t registerDisplayEventConnection( const sp<EventThreadConnection>& connection) = 0; virtual void setVsyncRate(uint32_t count, const sp<EventThreadConnection>& connection) = 0; - virtual void requestNextVsync(const sp<EventThreadConnection>& connection) = 0; + // Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer. + virtual void requestNextVsync(const sp<EventThreadConnection>& connection, + bool resetIdleTimer) = 0; }; namespace impl { @@ -129,7 +134,8 @@ public: status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override; void setVsyncRate(uint32_t count, const sp<EventThreadConnection>& connection) override; - void requestNextVsync(const sp<EventThreadConnection>& connection) override; + void requestNextVsync(const sp<EventThreadConnection>& connection, + bool resetIdleTimer) override; // called before the screen is turned off from main thread void onScreenReleased() override; @@ -166,6 +172,9 @@ private: // Implements VSyncSource::Callback void onVSyncEvent(nsecs_t timestamp) override; + // Acquires mutex and requests next vsync. + void requestNextVsyncInternal(const sp<EventThreadConnection>& connection) EXCLUDES(mMutex); + // TODO(b/113612090): Once the Scheduler is complete this pointer will become obsolete. VSyncSource* mVSyncSource GUARDED_BY(mMutex) = nullptr; std::unique_ptr<VSyncSource> mVSyncSourceUnique GUARDED_BY(mMutex) = nullptr; diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp index 36403cc346..66f42bbac1 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.cpp +++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp @@ -148,6 +148,10 @@ void MessageQueue::invalidate() { mEvents->requestNextVsync(); } +void MessageQueue::invalidateForHWC() { + mEvents->requestNextVsyncForHWC(); +} + void MessageQueue::refresh() { mHandler->dispatchRefresh(); } diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h index 24a383422a..0bf00b0a76 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.h +++ b/services/surfaceflinger/Scheduler/MessageQueue.h @@ -91,6 +91,7 @@ public: virtual void waitMessage() = 0; virtual status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) = 0; virtual void invalidate() = 0; + virtual void invalidateForHWC() = 0; virtual void refresh() = 0; }; @@ -134,6 +135,9 @@ public: // sends INVALIDATE message at next VSYNC void invalidate() override; + + // sends INVALIDATE message at next VSYNC, without resetting the idle timer in the Scheduler + void invalidateForHWC(); // sends REFRESH message at next VSYNC void refresh() override; }; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index c363ba57f7..fec53af617 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -238,6 +238,16 @@ void Scheduler::incrementFrameCounter() { mLayerHistory.incrementCounter(); } +void Scheduler::setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback) { + std::lock_guard<std::mutex> lock(mCallbackLock); + mExpiredTimerCallback = expiredTimerCallback; +} + +void Scheduler::setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback) { + std::lock_guard<std::mutex> lock(mCallbackLock); + mResetTimerCallback = resetTimerCallback; +} + void Scheduler::updateFrameSkipping(const int64_t skipCount) { ATRACE_INT("FrameSkipCount", skipCount); if (mSkipCount != skipCount) { @@ -314,12 +324,12 @@ void Scheduler::determineTimestampAverage(bool isAutoTimestamp, const nsecs_t fr // TODO(b/113612090): This are current numbers from trial and error while running videos // from YouTube at 24, 30, and 60 fps. if (mean > 14 && mean < 18) { - ATRACE_INT("FPS", 60); + ATRACE_INT("MediaFPS", 60); } else if (mean > 31 && mean < 34) { - ATRACE_INT("FPS", 30); + ATRACE_INT("MediaFPS", 30); return; } else if (mean > 39 && mean < 42) { - ATRACE_INT("FPS", 24); + ATRACE_INT("MediaFPS", 24); } } @@ -328,13 +338,19 @@ void Scheduler::resetIdleTimer() { mIdleTimer->reset(); ATRACE_INT("ExpiredIdleTimer", 0); } + + std::lock_guard<std::mutex> lock(mCallbackLock); + if (mResetTimerCallback) { + mResetTimerCallback(); + } } void Scheduler::expiredTimerCallback() { - // TODO(b/113612090): Each time a timer expired, we should record the information into - // a circular buffer. Once this has happened a given amount (TBD) of times, we can comfortably - // say that the device is sitting in idle. - ATRACE_INT("ExpiredIdleTimer", 1); + std::lock_guard<std::mutex> lock(mCallbackLock); + if (mExpiredTimerCallback) { + mExpiredTimerCallback(); + ATRACE_INT("ExpiredIdleTimer", 1); + } } } // namespace android diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 9d7dd4df64..3538f317aa 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -36,6 +36,9 @@ class EventControlThread; class Scheduler { public: + using ExpiredIdleTimerCallback = std::function<void()>; + using ResetIdleTimerCallback = std::function<void()>; + // Enum to indicate whether to start the transaction early, or at vsync time. enum class TransactionStart { EARLY, NORMAL }; @@ -111,6 +114,10 @@ public: const std::string layerName); // Increments counter in the layer history to indicate that SF has started a new frame. void incrementFrameCounter(); + // Callback that gets invoked once the idle timer expires. + void setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback); + // Callback that gets invoked once the idle timer is reset. + void setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback); protected: virtual std::unique_ptr<EventThread> makeEventThread( @@ -173,6 +180,10 @@ private: // interval, a callback is fired. Set this variable to >0 to use this feature. int64_t mSetIdleTimerMs = 0; std::unique_ptr<scheduler::IdleTimer> mIdleTimer; + + std::mutex mCallbackLock; + ExpiredIdleTimerCallback mExpiredTimerCallback GUARDED_BY(mCallbackLock); + ResetIdleTimerCallback mResetTimerCallback GUARDED_BY(mCallbackLock); }; } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index dc82b3267f..bd16d645f1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -729,6 +729,11 @@ void SurfaceFlinger::init() { ALOGE("Run StartPropertySetThread failed!"); } + if (mUseScheduler) { + mScheduler->setExpiredIdleTimerCallback([this]() { setRefreshRateTo(60.f /* fps */); }); + mScheduler->setResetIdleTimerCallback([this]() { setRefreshRateTo(90.f /* fps */); }); + } + ALOGV("Done initializing"); } @@ -934,14 +939,45 @@ int SurfaceFlinger::getActiveConfig(const sp<IBinder>& displayToken) { return display->getActiveConfig(); } -void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& display, int mode) { +status_t SurfaceFlinger::setActiveConfigAsync(const sp<IBinder>& displayToken, int mode) { + ATRACE_NAME("setActiveConfigAsync"); + postMessageAsync(new LambdaMessage([=] { setActiveConfigInternal(displayToken, mode); })); + return NO_ERROR; +} + +status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) { + ATRACE_NAME("setActiveConfigSync"); + postMessageSync(new LambdaMessage([&] { setActiveConfigInternal(displayToken, mode); })); + return NO_ERROR; +} + +void SurfaceFlinger::setActiveConfigInternal(const sp<IBinder>& displayToken, int mode) { + Vector<DisplayInfo> configs; + getDisplayConfigs(displayToken, &configs); + if (mode < 0 || mode >= static_cast<int>(configs.size())) { + ALOGE("Attempt to set active config %d for display with %zu configs", mode, configs.size()); + return; + } + + const auto display = getDisplayDevice(displayToken); + if (!display) { + ALOGE("Attempt to set active config %d for invalid display token %p", mode, + displayToken.get()); + return; + } if (display->isVirtual()) { - ALOGE("%s: Invalid operation on virtual display", __FUNCTION__); + ALOGW("Attempt to set active config %d for virtual display", mode); + return; + } + int currentDisplayPowerMode = display->getPowerMode(); + if (currentDisplayPowerMode != HWC_POWER_MODE_NORMAL) { + // Don't change active config when in AoD. return; } int currentMode = display->getActiveConfig(); if (mode == currentMode) { + // Don't update config if we are already running in the desired mode. return; } @@ -950,29 +986,9 @@ void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& display, i display->setActiveConfig(mode); getHwComposer().setActiveConfig(*displayId, mode); -} -status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) { - postMessageSync(new LambdaMessage([&] { - Vector<DisplayInfo> configs; - getDisplayConfigs(displayToken, &configs); - if (mode < 0 || mode >= static_cast<int>(configs.size())) { - ALOGE("Attempt to set active config %d for display with %zu configs", mode, - configs.size()); - return; - } - const auto display = getDisplayDevice(displayToken); - if (!display) { - ALOGE("Attempt to set active config %d for invalid display token %p", mode, - displayToken.get()); - } else if (display->isVirtual()) { - ALOGW("Attempt to set active config %d for virtual display", mode); - } else { - setActiveConfigInternal(display, mode); - } - })); - - return NO_ERROR; + ATRACE_INT("ActiveConfigMode", mode); + resyncToHardwareVsync(true); } status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken, @@ -1382,6 +1398,49 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { *compositorTiming = getBE().mCompositorTiming; } +void SurfaceFlinger::setRefreshRateTo(float newFps) { + const auto displayId = getInternalDisplayId(); + if (!displayId || mBootStage != BootStage::FINISHED) { + return; + } + // TODO(b/113612090): There should be a message queue flush here. Because this esentially + // runs on a mainthread, we cannot call postMessageSync. This can be resolved in a better + // manner, once the setActiveConfig is synchronous, and is executed at a known time in a + // refresh cycle. + + // Don't do any updating if the current fps is the same as the new one. + const auto activeConfig = getHwComposer().getActiveConfig(*displayId); + const nsecs_t currentVsyncPeriod = activeConfig->getVsyncPeriod(); + if (currentVsyncPeriod == 0) { + return; + } + // TODO(b/113612090): Consider having an enum value for correct refresh rates, rather than + // floating numbers. + const float currentFps = 1e9 / currentVsyncPeriod; + if (std::abs(currentFps - newFps) <= 1) { + return; + } + + auto configs = getHwComposer().getConfigs(*displayId); + for (int i = 0; i < configs.size(); i++) { + const nsecs_t vsyncPeriod = configs.at(i)->getVsyncPeriod(); + if (vsyncPeriod == 0) { + continue; + } + const float fps = 1e9 / vsyncPeriod; + // TODO(b/113612090): There should be a better way at determining which config + // has the right refresh rate. + if (std::abs(fps - newFps) <= 1) { + const auto display = getBuiltInDisplay(HWC_DISPLAY_PRIMARY); + if (!display) return; + // This is posted in async function to avoid deadlock when getDisplayDevice + // requires mStateLock. + setActiveConfigAsync(display, i); + ATRACE_INT("FPS", newFps); + } + } +} + void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId, HWC2::Connection connection) { ALOGV("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId, @@ -1413,7 +1472,7 @@ void SurfaceFlinger::onRefreshReceived(int sequenceId, hwc2_display_t /*hwcDispl if (sequenceId != getBE().mComposerSequenceId) { return; } - repaintEverything(); + repaintEverythingForHWC(); } void SurfaceFlinger::setVsyncEnabled(EventThread::DisplayType /*displayType*/, bool enabled) { @@ -5177,6 +5236,11 @@ void SurfaceFlinger::repaintEverything() { signalTransaction(); } +void SurfaceFlinger::repaintEverythingForHWC() { + mRepaintEverything = true; + mEventQueue->invalidateForHWC(); +} + // A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope class WindowDisconnector { public: diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index ac730ab21d..eb7127e2a6 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -311,6 +311,9 @@ public: // force full composition on all displays void repaintEverything(); + // force full composition on all displays without resetting the scheduler idle timer. + void repaintEverythingForHWC(); + surfaceflinger::Factory& getFactory() { return mFactory; } // The CompositionEngine encapsulates all composition related interfaces and actions. @@ -502,8 +505,10 @@ private: // called on the main thread in response to initializeDisplays() void onInitializeDisplays(); + // setActiveConfigInternal() posted on a main thread for async execution + status_t setActiveConfigAsync(const sp<IBinder>& displayToken, int mode); // called on the main thread in response to setActiveConfig() - void setActiveConfigInternal(const sp<DisplayDevice>& display, int mode); + void setActiveConfigInternal(const sp<IBinder>& displayToken, int mode); // called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp<DisplayDevice>& display, int mode); @@ -763,6 +768,9 @@ public: void resyncWithRateLimit(); void getCompositorTiming(CompositorTiming* compositorTiming); private: + // Sets the refresh rate to newFps by switching active configs, if they are available for + // the desired refresh rate. + void setRefreshRateTo(float newFps); /* ------------------------------------------------------------------------ * Debugging & dumpsys diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index acbed51e9d..2d26bb37e1 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -200,7 +200,7 @@ TEST_F(EventThreadTest, canCreateAndDestroyThreadWithNoEventsSent) { TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) { // Signal that we want the next vsync event to be posted to the connection - mThread->requestNextVsync(mConnection); + mThread->requestNextVsync(mConnection, false); // EventThread should immediately request a resync. EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value()); diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index bb6e1831df..48d45fa980 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -37,7 +37,7 @@ public: MOCK_METHOD1(registerDisplayEventConnection, status_t(const sp<android::EventThreadConnection> &)); MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &)); - MOCK_METHOD1(requestNextVsync, void(const sp<android::EventThreadConnection> &)); + MOCK_METHOD2(requestNextVsync, void(const sp<android::EventThreadConnection> &, bool)); }; } // namespace mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h index dc8d606547..8c113e2006 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h +++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h @@ -35,6 +35,7 @@ public: MOCK_METHOD0(waitMessage, void()); MOCK_METHOD2(postMessage, status_t(const sp<MessageBase>&, nsecs_t)); MOCK_METHOD0(invalidate, void()); + MOCK_METHOD0(invalidateForHWC, void()); MOCK_METHOD0(refresh, void()); }; |