Loading services/surfaceflinger/DisplayHardware/HWComposer.cpp +25 −4 Original line number Diff line number Diff line Loading @@ -247,8 +247,8 @@ nsecs_t HWComposer::getRefreshTimestamp(DisplayId displayId) const { // the refresh period and whatever closest timestamp we have. std::lock_guard lock(displayData.lastHwVsyncLock); nsecs_t now = systemTime(CLOCK_MONOTONIC); auto vsyncPeriod = getActiveConfig(displayId)->getVsyncPeriod(); return now - ((now - displayData.lastHwVsync) % vsyncPeriod); auto vsyncPeriodNanos = getDisplayVsyncPeriod(displayId); return now - ((now - displayData.lastHwVsync) % vsyncPeriodNanos); } bool HWComposer::isConnected(DisplayId displayId) const { Loading Loading @@ -291,6 +291,23 @@ std::shared_ptr<const HWC2::Display::Config> HWComposer::getActiveConfig( return config; } // Composer 2.4 bool HWComposer::isVsyncPeriodSwitchSupported(DisplayId displayId) const { return mDisplayData.at(displayId).hwcDisplay->isVsyncPeriodSwitchSupported(); } nsecs_t HWComposer::getDisplayVsyncPeriod(DisplayId displayId) const { nsecs_t vsyncPeriodNanos; auto error = mDisplayData.at(displayId).hwcDisplay->getDisplayVsyncPeriod(&vsyncPeriodNanos); if (error != HWC2::Error::None) { LOG_DISPLAY_ERROR(displayId, "Failed to get Vsync Period"); return 0; } return vsyncPeriodNanos; } int HWComposer::getActiveConfigIndex(DisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, -1); Loading Loading @@ -541,7 +558,9 @@ status_t HWComposer::setPowerMode(DisplayId displayId, int32_t intMode) { return NO_ERROR; } status_t HWComposer::setActiveConfig(DisplayId displayId, size_t configId) { status_t HWComposer::setActiveConfigWithConstraints( DisplayId displayId, size_t configId, const HWC2::VsyncPeriodChangeConstraints& constraints, HWC2::VsyncPeriodChangeTimeline* outTimeline) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); auto& displayData = mDisplayData[displayId]; Loading @@ -550,7 +569,9 @@ status_t HWComposer::setActiveConfig(DisplayId displayId, size_t configId) { return BAD_INDEX; } auto error = displayData.hwcDisplay->setActiveConfig(displayData.configMap[configId]); auto error = displayData.hwcDisplay->setActiveConfigWithConstraints(displayData.configMap[configId], constraints, outTimeline); RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; } Loading services/surfaceflinger/DisplayHardware/HWComposer.h +15 −6 Original line number Diff line number Diff line Loading @@ -102,9 +102,6 @@ public: // set power mode virtual status_t setPowerMode(DisplayId displayId, int mode) = 0; // set active config virtual status_t setActiveConfig(DisplayId displayId, size_t configId) = 0; // Sets a color transform to be applied to the result of composition virtual status_t setColorTransform(DisplayId displayId, const mat4& transform) = 0; Loading Loading @@ -180,6 +177,14 @@ public: virtual bool isUsingVrComposer() const = 0; // Composer 2.4 virtual bool isVsyncPeriodSwitchSupported(DisplayId displayId) const = 0; virtual nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const = 0; virtual status_t setActiveConfigWithConstraints( DisplayId displayId, size_t configId, const HWC2::VsyncPeriodChangeConstraints& constraints, HWC2::VsyncPeriodChangeTimeline* outTimeline) = 0; // for debugging ---------------------------------------------------------- virtual void dump(std::string& out) const = 0; Loading Loading @@ -232,9 +237,6 @@ public: // set power mode status_t setPowerMode(DisplayId displayId, int mode) override; // set active config status_t setActiveConfig(DisplayId displayId, size_t configId) override; // Sets a color transform to be applied to the result of composition status_t setColorTransform(DisplayId displayId, const mat4& transform) override; Loading Loading @@ -305,6 +307,13 @@ public: bool isUsingVrComposer() const override; // Composer 2.4 bool isVsyncPeriodSwitchSupported(DisplayId displayId) const override; nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const override; status_t setActiveConfigWithConstraints(DisplayId displayId, size_t configId, const HWC2::VsyncPeriodChangeConstraints& constraints, HWC2::VsyncPeriodChangeTimeline* outTimeline) override; // for debugging ---------------------------------------------------------- void dump(std::string& out) const override; Loading services/surfaceflinger/Scheduler/Scheduler.cpp +38 −13 Original line number Diff line number Diff line Loading @@ -59,11 +59,13 @@ namespace android { Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, const scheduler::RefreshRateConfigs& refreshRateConfig) const scheduler::RefreshRateConfigs& refreshRateConfig, ISchedulerCallback& schedulerCallback) : mPrimaryDispSync(new impl::DispSync("SchedulerDispSync", sysprop::running_without_sync_framework(true))), mEventControlThread(new impl::EventControlThread(std::move(function))), mSupportKernelTimer(sysprop::support_kernel_idle_timer(false)), mSchedulerCallback(schedulerCallback), mRefreshRateConfigs(refreshRateConfig) { using namespace sysprop; Loading Loading @@ -104,10 +106,12 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, Scheduler::Scheduler(std::unique_ptr<DispSync> primaryDispSync, std::unique_ptr<EventControlThread> eventControlThread, const scheduler::RefreshRateConfigs& configs) const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& schedulerCallback) : mPrimaryDispSync(std::move(primaryDispSync)), mEventControlThread(std::move(eventControlThread)), mSupportKernelTimer(false), mSchedulerCallback(schedulerCallback), mRefreshRateConfigs(configs) {} Scheduler::~Scheduler() { Loading Loading @@ -368,12 +372,7 @@ void Scheduler::chooseRefreshRateForContent() { mFeatures.configId = newConfigId; }; auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId); changeRefreshRate(newRefreshRate, ConfigEvent::Changed); } void Scheduler::setSchedulerCallback(android::Scheduler::ISchedulerCallback* callback) { std::lock_guard<std::mutex> lock(mCallbackLock); mSchedulerCallback = callback; mSchedulerCallback.changeRefreshRate(newRefreshRate, ConfigEvent::Changed); } void Scheduler::resetIdleTimer() { Loading Loading @@ -486,7 +485,7 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO } } const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId); changeRefreshRate(newRefreshRate, event); mSchedulerCallback.changeRefreshRate(newRefreshRate, event); } HwcConfigIndexType Scheduler::calculateRefreshRateType() { Loading Loading @@ -526,10 +525,36 @@ std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() { return mFeatures.configId; } void Scheduler::changeRefreshRate(const RefreshRate& refreshRate, ConfigEvent configEvent) { std::lock_guard<std::mutex> lock(mCallbackLock); if (mSchedulerCallback) { mSchedulerCallback->changeRefreshRate(refreshRate, configEvent); void Scheduler::onNewVsyncPeriodChangeTimeline(const HWC2::VsyncPeriodChangeTimeline& timeline) { if (timeline.refreshRequired) { mSchedulerCallback.repaintEverythingForHWC(); } std::lock_guard<std::mutex> lock(mVsyncTimelineLock); mLastVsyncPeriodChangeTimeline = std::make_optional(timeline); const auto maxAppliedTime = systemTime() + MAX_VSYNC_APPLIED_TIME.count(); if (timeline.newVsyncAppliedTimeNanos > maxAppliedTime) { mLastVsyncPeriodChangeTimeline->newVsyncAppliedTimeNanos = maxAppliedTime; } } void Scheduler::onDisplayRefreshed(nsecs_t timestamp) { bool callRepaint = false; { std::lock_guard<std::mutex> lock(mVsyncTimelineLock); if (mLastVsyncPeriodChangeTimeline && mLastVsyncPeriodChangeTimeline->refreshRequired) { if (mLastVsyncPeriodChangeTimeline->refreshTimeNanos < timestamp) { mLastVsyncPeriodChangeTimeline->refreshRequired = false; } else { // We need to send another refresh as refreshTimeNanos is still in the future callRepaint = true; } } } if (callRepaint) { mSchedulerCallback.repaintEverythingForHWC(); } } Loading services/surfaceflinger/Scheduler/Scheduler.h +22 −15 Original line number Diff line number Diff line Loading @@ -41,22 +41,24 @@ class FenceTime; class InjectVSyncSource; struct DisplayStateInfo; class Scheduler { public: using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using ConfigEvent = scheduler::RefreshRateConfigEvent; class ISchedulerCallback { public: virtual ~ISchedulerCallback() = default; virtual void changeRefreshRate(const RefreshRate&, ConfigEvent) = 0; virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&, scheduler::RefreshRateConfigEvent) = 0; virtual void repaintEverythingForHWC() = 0; }; class Scheduler { public: using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using ConfigEvent = scheduler::RefreshRateConfigEvent; // Indicates whether to start the transaction early, or at vsync time. enum class TransactionStart { EARLY, NORMAL }; Scheduler(impl::EventControlThread::SetVSyncEnabledFunction, const scheduler::RefreshRateConfigs&); const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback); virtual ~Scheduler(); Loading Loading @@ -114,9 +116,6 @@ public: // Detects content using layer history, and selects a matching refresh rate. void chooseRefreshRateForContent(); // Called by Scheduler to control SurfaceFlinger operations. void setSchedulerCallback(ISchedulerCallback*); bool isIdleTimerEnabled() const { return mIdleTimer.has_value(); } void resetIdleTimer(); Loading @@ -131,6 +130,12 @@ public: // Get the appropriate refresh for current conditions. std::optional<HwcConfigIndexType> getPreferredConfigId(); // Notifies the scheduler about a refresh rate timeline change. void onNewVsyncPeriodChangeTimeline(const HWC2::VsyncPeriodChangeTimeline& timeline); // Notifies the scheduler when the display was refreshed void onDisplayRefreshed(nsecs_t timestamp); private: friend class TestableScheduler; Loading @@ -142,7 +147,7 @@ private: // Used by tests to inject mocks. Scheduler(std::unique_ptr<DispSync>, std::unique_ptr<EventControlThread>, const scheduler::RefreshRateConfigs&); const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback); std::unique_ptr<VSyncSource> makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync); Loading @@ -165,8 +170,6 @@ private: void setVsyncPeriod(nsecs_t period); HwcConfigIndexType calculateRefreshRateType() REQUIRES(mFeatureStateLock); // Acquires a lock and calls the ChangeRefreshRateCallback with given parameters. void changeRefreshRate(const RefreshRate&, ConfigEvent); // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection. struct Connection { Loading Loading @@ -203,8 +206,7 @@ private: // Timer used to monitor display power mode. std::optional<scheduler::OneShotTimer> mDisplayPowerTimer; std::mutex mCallbackLock; ISchedulerCallback* mSchedulerCallback GUARDED_BY(mCallbackLock) = nullptr; ISchedulerCallback& mSchedulerCallback; // In order to make sure that the features don't override themselves, we need a state machine // to keep track which feature requested the config change. Loading @@ -223,6 +225,11 @@ private: } mFeatures GUARDED_BY(mFeatureStateLock); const scheduler::RefreshRateConfigs& mRefreshRateConfigs; std::mutex mVsyncTimelineLock; std::optional<HWC2::VsyncPeriodChangeTimeline> mLastVsyncPeriodChangeTimeline GUARDED_BY(mVsyncTimelineLock); static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms; }; } // namespace android services/surfaceflinger/SurfaceFlinger.cpp +55 −13 Original line number Diff line number Diff line Loading @@ -1004,11 +1004,25 @@ bool SurfaceFlinger::performSetActiveConfig() { LOG_ALWAYS_FATAL_IF(!displayId); ATRACE_INT("ActiveConfigFPS_HWC", refreshRate.fps); getHwComposer().setActiveConfig(*displayId, mUpcomingActiveConfig.configId.value()); // we need to submit an empty frame to HWC to start the process // TODO(b/142753666) use constrains HWC2::VsyncPeriodChangeConstraints constraints; constraints.desiredTimeNanos = systemTime(); constraints.seamlessRequired = false; HWC2::VsyncPeriodChangeTimeline outTimeline; auto status = getHwComposer().setActiveConfigWithConstraints(*displayId, mUpcomingActiveConfig.configId.value(), constraints, &outTimeline); if (status != NO_ERROR) { LOG_ALWAYS_FATAL("setActiveConfigWithConstraints failed: %d", status); return false; } mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline); // Scheduler will submit an empty frame to HWC if needed. mCheckPendingFence = true; mEventQueue->invalidate(); return false; } Loading Loading @@ -1361,8 +1375,7 @@ nsecs_t SurfaceFlinger::getVsyncPeriod() const { return 0; } const auto config = getHwComposer().getActiveConfig(*displayId); return config ? config->getVsyncPeriod() : 0; return getHwComposer().getDisplayVsyncPeriod(*displayId); } void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId, Loading Loading @@ -1448,9 +1461,13 @@ void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDis } void SurfaceFlinger::onVsyncPeriodTimingChangedReceived( int32_t /*sequenceId*/, hwc2_display_t /*display*/, const hwc_vsync_period_change_timeline_t& /*updatedTimeline*/) { // TODO(b/142753004): use timeline when changing refresh rate int32_t sequenceId, hwc2_display_t /*display*/, const hwc_vsync_period_change_timeline_t& updatedTimeline) { Mutex::Autolock lock(mStateLock); if (sequenceId != getBE().mComposerSequenceId) { return; } mScheduler->onNewVsyncPeriodChangeTimeline(updatedTimeline); } void SurfaceFlinger::onRefreshReceived(int sequenceId, hwc2_display_t /*hwcDisplayId*/) { Loading Loading @@ -1761,11 +1778,17 @@ void SurfaceFlinger::handleMessageRefresh() { mGeometryInvalid = false; // Store the present time just before calling to the composition engine so we could notify // the scheduler. const auto presentTime = systemTime(); mCompositionEngine->present(refreshArgs); mTimeStats->recordFrameDuration(mFrameStartTime, systemTime()); // Reset the frame start time now that we've recorded this frame. mFrameStartTime = 0; mScheduler->onDisplayRefreshed(presentTime); postFrame(); postComposition(); Loading Loading @@ -2551,7 +2574,7 @@ void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) { // start the EventThread mScheduler = getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); }, *mRefreshRateConfigs); *mRefreshRateConfigs, *this); mAppConnectionHandle = mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(), mPhaseOffsets->getOffsetThresholdForNextVsync(), Loading @@ -2570,8 +2593,6 @@ void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) { mRegionSamplingThread = new RegionSamplingThread(*this, *mScheduler, RegionSamplingThread::EnvironmentTimingTunables()); mScheduler->setSchedulerCallback(this); } void SurfaceFlinger::commitTransaction() Loading Loading @@ -4316,8 +4337,8 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co " refresh-rate : %f fps\n" " x-dpi : %f\n" " y-dpi : %f\n", 1e9 / activeConfig->getVsyncPeriod(), activeConfig->getDpiX(), activeConfig->getDpiY()); 1e9 / getHwComposer().getDisplayVsyncPeriod(*displayId), activeConfig->getDpiX(), activeConfig->getDpiY()); } StringAppendF(&result, " transaction time: %f us\n", inTransactionDuration / 1000.0); Loading Loading @@ -5438,6 +5459,27 @@ void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& disp void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& display, const std::vector<int32_t>& allowedConfigs) { if (!display->isPrimary()) { // TODO(b/144711714): For non-primary displays we should be able to set an active config // as well. For now, just call directly to setActiveConfigWithConstraints but ideally // it should go thru setDesiredActiveConfig, similar to primary display. ALOGV("setAllowedDisplayConfigsInternal for non-primary display"); const auto displayId = display->getId(); LOG_ALWAYS_FATAL_IF(!displayId); HWC2::VsyncPeriodChangeConstraints constraints; constraints.desiredTimeNanos = systemTime(); constraints.seamlessRequired = false; HWC2::VsyncPeriodChangeTimeline timeline = {0, 0, 0}; getHwComposer().setActiveConfigWithConstraints(*displayId, allowedConfigs[0], constraints, &timeline); if (timeline.refreshRequired) { repaintEverythingForHWC(); } auto configId = HwcConfigIndexType(allowedConfigs[0]); display->setActiveConfig(configId); mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, configId); return; } Loading Loading
services/surfaceflinger/DisplayHardware/HWComposer.cpp +25 −4 Original line number Diff line number Diff line Loading @@ -247,8 +247,8 @@ nsecs_t HWComposer::getRefreshTimestamp(DisplayId displayId) const { // the refresh period and whatever closest timestamp we have. std::lock_guard lock(displayData.lastHwVsyncLock); nsecs_t now = systemTime(CLOCK_MONOTONIC); auto vsyncPeriod = getActiveConfig(displayId)->getVsyncPeriod(); return now - ((now - displayData.lastHwVsync) % vsyncPeriod); auto vsyncPeriodNanos = getDisplayVsyncPeriod(displayId); return now - ((now - displayData.lastHwVsync) % vsyncPeriodNanos); } bool HWComposer::isConnected(DisplayId displayId) const { Loading Loading @@ -291,6 +291,23 @@ std::shared_ptr<const HWC2::Display::Config> HWComposer::getActiveConfig( return config; } // Composer 2.4 bool HWComposer::isVsyncPeriodSwitchSupported(DisplayId displayId) const { return mDisplayData.at(displayId).hwcDisplay->isVsyncPeriodSwitchSupported(); } nsecs_t HWComposer::getDisplayVsyncPeriod(DisplayId displayId) const { nsecs_t vsyncPeriodNanos; auto error = mDisplayData.at(displayId).hwcDisplay->getDisplayVsyncPeriod(&vsyncPeriodNanos); if (error != HWC2::Error::None) { LOG_DISPLAY_ERROR(displayId, "Failed to get Vsync Period"); return 0; } return vsyncPeriodNanos; } int HWComposer::getActiveConfigIndex(DisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, -1); Loading Loading @@ -541,7 +558,9 @@ status_t HWComposer::setPowerMode(DisplayId displayId, int32_t intMode) { return NO_ERROR; } status_t HWComposer::setActiveConfig(DisplayId displayId, size_t configId) { status_t HWComposer::setActiveConfigWithConstraints( DisplayId displayId, size_t configId, const HWC2::VsyncPeriodChangeConstraints& constraints, HWC2::VsyncPeriodChangeTimeline* outTimeline) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); auto& displayData = mDisplayData[displayId]; Loading @@ -550,7 +569,9 @@ status_t HWComposer::setActiveConfig(DisplayId displayId, size_t configId) { return BAD_INDEX; } auto error = displayData.hwcDisplay->setActiveConfig(displayData.configMap[configId]); auto error = displayData.hwcDisplay->setActiveConfigWithConstraints(displayData.configMap[configId], constraints, outTimeline); RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; } Loading
services/surfaceflinger/DisplayHardware/HWComposer.h +15 −6 Original line number Diff line number Diff line Loading @@ -102,9 +102,6 @@ public: // set power mode virtual status_t setPowerMode(DisplayId displayId, int mode) = 0; // set active config virtual status_t setActiveConfig(DisplayId displayId, size_t configId) = 0; // Sets a color transform to be applied to the result of composition virtual status_t setColorTransform(DisplayId displayId, const mat4& transform) = 0; Loading Loading @@ -180,6 +177,14 @@ public: virtual bool isUsingVrComposer() const = 0; // Composer 2.4 virtual bool isVsyncPeriodSwitchSupported(DisplayId displayId) const = 0; virtual nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const = 0; virtual status_t setActiveConfigWithConstraints( DisplayId displayId, size_t configId, const HWC2::VsyncPeriodChangeConstraints& constraints, HWC2::VsyncPeriodChangeTimeline* outTimeline) = 0; // for debugging ---------------------------------------------------------- virtual void dump(std::string& out) const = 0; Loading Loading @@ -232,9 +237,6 @@ public: // set power mode status_t setPowerMode(DisplayId displayId, int mode) override; // set active config status_t setActiveConfig(DisplayId displayId, size_t configId) override; // Sets a color transform to be applied to the result of composition status_t setColorTransform(DisplayId displayId, const mat4& transform) override; Loading Loading @@ -305,6 +307,13 @@ public: bool isUsingVrComposer() const override; // Composer 2.4 bool isVsyncPeriodSwitchSupported(DisplayId displayId) const override; nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const override; status_t setActiveConfigWithConstraints(DisplayId displayId, size_t configId, const HWC2::VsyncPeriodChangeConstraints& constraints, HWC2::VsyncPeriodChangeTimeline* outTimeline) override; // for debugging ---------------------------------------------------------- void dump(std::string& out) const override; Loading
services/surfaceflinger/Scheduler/Scheduler.cpp +38 −13 Original line number Diff line number Diff line Loading @@ -59,11 +59,13 @@ namespace android { Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, const scheduler::RefreshRateConfigs& refreshRateConfig) const scheduler::RefreshRateConfigs& refreshRateConfig, ISchedulerCallback& schedulerCallback) : mPrimaryDispSync(new impl::DispSync("SchedulerDispSync", sysprop::running_without_sync_framework(true))), mEventControlThread(new impl::EventControlThread(std::move(function))), mSupportKernelTimer(sysprop::support_kernel_idle_timer(false)), mSchedulerCallback(schedulerCallback), mRefreshRateConfigs(refreshRateConfig) { using namespace sysprop; Loading Loading @@ -104,10 +106,12 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, Scheduler::Scheduler(std::unique_ptr<DispSync> primaryDispSync, std::unique_ptr<EventControlThread> eventControlThread, const scheduler::RefreshRateConfigs& configs) const scheduler::RefreshRateConfigs& configs, ISchedulerCallback& schedulerCallback) : mPrimaryDispSync(std::move(primaryDispSync)), mEventControlThread(std::move(eventControlThread)), mSupportKernelTimer(false), mSchedulerCallback(schedulerCallback), mRefreshRateConfigs(configs) {} Scheduler::~Scheduler() { Loading Loading @@ -368,12 +372,7 @@ void Scheduler::chooseRefreshRateForContent() { mFeatures.configId = newConfigId; }; auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId); changeRefreshRate(newRefreshRate, ConfigEvent::Changed); } void Scheduler::setSchedulerCallback(android::Scheduler::ISchedulerCallback* callback) { std::lock_guard<std::mutex> lock(mCallbackLock); mSchedulerCallback = callback; mSchedulerCallback.changeRefreshRate(newRefreshRate, ConfigEvent::Changed); } void Scheduler::resetIdleTimer() { Loading Loading @@ -486,7 +485,7 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO } } const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId); changeRefreshRate(newRefreshRate, event); mSchedulerCallback.changeRefreshRate(newRefreshRate, event); } HwcConfigIndexType Scheduler::calculateRefreshRateType() { Loading Loading @@ -526,10 +525,36 @@ std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() { return mFeatures.configId; } void Scheduler::changeRefreshRate(const RefreshRate& refreshRate, ConfigEvent configEvent) { std::lock_guard<std::mutex> lock(mCallbackLock); if (mSchedulerCallback) { mSchedulerCallback->changeRefreshRate(refreshRate, configEvent); void Scheduler::onNewVsyncPeriodChangeTimeline(const HWC2::VsyncPeriodChangeTimeline& timeline) { if (timeline.refreshRequired) { mSchedulerCallback.repaintEverythingForHWC(); } std::lock_guard<std::mutex> lock(mVsyncTimelineLock); mLastVsyncPeriodChangeTimeline = std::make_optional(timeline); const auto maxAppliedTime = systemTime() + MAX_VSYNC_APPLIED_TIME.count(); if (timeline.newVsyncAppliedTimeNanos > maxAppliedTime) { mLastVsyncPeriodChangeTimeline->newVsyncAppliedTimeNanos = maxAppliedTime; } } void Scheduler::onDisplayRefreshed(nsecs_t timestamp) { bool callRepaint = false; { std::lock_guard<std::mutex> lock(mVsyncTimelineLock); if (mLastVsyncPeriodChangeTimeline && mLastVsyncPeriodChangeTimeline->refreshRequired) { if (mLastVsyncPeriodChangeTimeline->refreshTimeNanos < timestamp) { mLastVsyncPeriodChangeTimeline->refreshRequired = false; } else { // We need to send another refresh as refreshTimeNanos is still in the future callRepaint = true; } } } if (callRepaint) { mSchedulerCallback.repaintEverythingForHWC(); } } Loading
services/surfaceflinger/Scheduler/Scheduler.h +22 −15 Original line number Diff line number Diff line Loading @@ -41,22 +41,24 @@ class FenceTime; class InjectVSyncSource; struct DisplayStateInfo; class Scheduler { public: using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using ConfigEvent = scheduler::RefreshRateConfigEvent; class ISchedulerCallback { public: virtual ~ISchedulerCallback() = default; virtual void changeRefreshRate(const RefreshRate&, ConfigEvent) = 0; virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&, scheduler::RefreshRateConfigEvent) = 0; virtual void repaintEverythingForHWC() = 0; }; class Scheduler { public: using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using ConfigEvent = scheduler::RefreshRateConfigEvent; // Indicates whether to start the transaction early, or at vsync time. enum class TransactionStart { EARLY, NORMAL }; Scheduler(impl::EventControlThread::SetVSyncEnabledFunction, const scheduler::RefreshRateConfigs&); const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback); virtual ~Scheduler(); Loading Loading @@ -114,9 +116,6 @@ public: // Detects content using layer history, and selects a matching refresh rate. void chooseRefreshRateForContent(); // Called by Scheduler to control SurfaceFlinger operations. void setSchedulerCallback(ISchedulerCallback*); bool isIdleTimerEnabled() const { return mIdleTimer.has_value(); } void resetIdleTimer(); Loading @@ -131,6 +130,12 @@ public: // Get the appropriate refresh for current conditions. std::optional<HwcConfigIndexType> getPreferredConfigId(); // Notifies the scheduler about a refresh rate timeline change. void onNewVsyncPeriodChangeTimeline(const HWC2::VsyncPeriodChangeTimeline& timeline); // Notifies the scheduler when the display was refreshed void onDisplayRefreshed(nsecs_t timestamp); private: friend class TestableScheduler; Loading @@ -142,7 +147,7 @@ private: // Used by tests to inject mocks. Scheduler(std::unique_ptr<DispSync>, std::unique_ptr<EventControlThread>, const scheduler::RefreshRateConfigs&); const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback); std::unique_ptr<VSyncSource> makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync); Loading @@ -165,8 +170,6 @@ private: void setVsyncPeriod(nsecs_t period); HwcConfigIndexType calculateRefreshRateType() REQUIRES(mFeatureStateLock); // Acquires a lock and calls the ChangeRefreshRateCallback with given parameters. void changeRefreshRate(const RefreshRate&, ConfigEvent); // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection. struct Connection { Loading Loading @@ -203,8 +206,7 @@ private: // Timer used to monitor display power mode. std::optional<scheduler::OneShotTimer> mDisplayPowerTimer; std::mutex mCallbackLock; ISchedulerCallback* mSchedulerCallback GUARDED_BY(mCallbackLock) = nullptr; ISchedulerCallback& mSchedulerCallback; // In order to make sure that the features don't override themselves, we need a state machine // to keep track which feature requested the config change. Loading @@ -223,6 +225,11 @@ private: } mFeatures GUARDED_BY(mFeatureStateLock); const scheduler::RefreshRateConfigs& mRefreshRateConfigs; std::mutex mVsyncTimelineLock; std::optional<HWC2::VsyncPeriodChangeTimeline> mLastVsyncPeriodChangeTimeline GUARDED_BY(mVsyncTimelineLock); static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms; }; } // namespace android
services/surfaceflinger/SurfaceFlinger.cpp +55 −13 Original line number Diff line number Diff line Loading @@ -1004,11 +1004,25 @@ bool SurfaceFlinger::performSetActiveConfig() { LOG_ALWAYS_FATAL_IF(!displayId); ATRACE_INT("ActiveConfigFPS_HWC", refreshRate.fps); getHwComposer().setActiveConfig(*displayId, mUpcomingActiveConfig.configId.value()); // we need to submit an empty frame to HWC to start the process // TODO(b/142753666) use constrains HWC2::VsyncPeriodChangeConstraints constraints; constraints.desiredTimeNanos = systemTime(); constraints.seamlessRequired = false; HWC2::VsyncPeriodChangeTimeline outTimeline; auto status = getHwComposer().setActiveConfigWithConstraints(*displayId, mUpcomingActiveConfig.configId.value(), constraints, &outTimeline); if (status != NO_ERROR) { LOG_ALWAYS_FATAL("setActiveConfigWithConstraints failed: %d", status); return false; } mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline); // Scheduler will submit an empty frame to HWC if needed. mCheckPendingFence = true; mEventQueue->invalidate(); return false; } Loading Loading @@ -1361,8 +1375,7 @@ nsecs_t SurfaceFlinger::getVsyncPeriod() const { return 0; } const auto config = getHwComposer().getActiveConfig(*displayId); return config ? config->getVsyncPeriod() : 0; return getHwComposer().getDisplayVsyncPeriod(*displayId); } void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId, Loading Loading @@ -1448,9 +1461,13 @@ void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDis } void SurfaceFlinger::onVsyncPeriodTimingChangedReceived( int32_t /*sequenceId*/, hwc2_display_t /*display*/, const hwc_vsync_period_change_timeline_t& /*updatedTimeline*/) { // TODO(b/142753004): use timeline when changing refresh rate int32_t sequenceId, hwc2_display_t /*display*/, const hwc_vsync_period_change_timeline_t& updatedTimeline) { Mutex::Autolock lock(mStateLock); if (sequenceId != getBE().mComposerSequenceId) { return; } mScheduler->onNewVsyncPeriodChangeTimeline(updatedTimeline); } void SurfaceFlinger::onRefreshReceived(int sequenceId, hwc2_display_t /*hwcDisplayId*/) { Loading Loading @@ -1761,11 +1778,17 @@ void SurfaceFlinger::handleMessageRefresh() { mGeometryInvalid = false; // Store the present time just before calling to the composition engine so we could notify // the scheduler. const auto presentTime = systemTime(); mCompositionEngine->present(refreshArgs); mTimeStats->recordFrameDuration(mFrameStartTime, systemTime()); // Reset the frame start time now that we've recorded this frame. mFrameStartTime = 0; mScheduler->onDisplayRefreshed(presentTime); postFrame(); postComposition(); Loading Loading @@ -2551,7 +2574,7 @@ void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) { // start the EventThread mScheduler = getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); }, *mRefreshRateConfigs); *mRefreshRateConfigs, *this); mAppConnectionHandle = mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(), mPhaseOffsets->getOffsetThresholdForNextVsync(), Loading @@ -2570,8 +2593,6 @@ void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) { mRegionSamplingThread = new RegionSamplingThread(*this, *mScheduler, RegionSamplingThread::EnvironmentTimingTunables()); mScheduler->setSchedulerCallback(this); } void SurfaceFlinger::commitTransaction() Loading Loading @@ -4316,8 +4337,8 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co " refresh-rate : %f fps\n" " x-dpi : %f\n" " y-dpi : %f\n", 1e9 / activeConfig->getVsyncPeriod(), activeConfig->getDpiX(), activeConfig->getDpiY()); 1e9 / getHwComposer().getDisplayVsyncPeriod(*displayId), activeConfig->getDpiX(), activeConfig->getDpiY()); } StringAppendF(&result, " transaction time: %f us\n", inTransactionDuration / 1000.0); Loading Loading @@ -5438,6 +5459,27 @@ void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& disp void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& display, const std::vector<int32_t>& allowedConfigs) { if (!display->isPrimary()) { // TODO(b/144711714): For non-primary displays we should be able to set an active config // as well. For now, just call directly to setActiveConfigWithConstraints but ideally // it should go thru setDesiredActiveConfig, similar to primary display. ALOGV("setAllowedDisplayConfigsInternal for non-primary display"); const auto displayId = display->getId(); LOG_ALWAYS_FATAL_IF(!displayId); HWC2::VsyncPeriodChangeConstraints constraints; constraints.desiredTimeNanos = systemTime(); constraints.seamlessRequired = false; HWC2::VsyncPeriodChangeTimeline timeline = {0, 0, 0}; getHwComposer().setActiveConfigWithConstraints(*displayId, allowedConfigs[0], constraints, &timeline); if (timeline.refreshRequired) { repaintEverythingForHWC(); } auto configId = HwcConfigIndexType(allowedConfigs[0]); display->setActiveConfig(configId); mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, configId); return; } Loading