Loading services/surfaceflinger/Display/DisplayModeController.cpp +61 −0 Original line number Diff line number Diff line Loading @@ -22,7 +22,9 @@ #include "Display/DisplaySnapshot.h" #include "DisplayHardware/HWComposer.h" #include <android-base/properties.h> #include <common/FlagManager.h> #include <common/trace.h> #include <ftl/concat.h> #include <ftl/expected.h> #include <log/log.h> Loading Loading @@ -237,4 +239,63 @@ void DisplayModeController::setActiveModeLocked(PhysicalDisplayId displayId, Dis } } void DisplayModeController::updateKernelIdleTimer(PhysicalDisplayId displayId) { std::lock_guard lock(mDisplayLock); const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get(); const auto controllerOpt = displayPtr->selectorPtr->kernelIdleTimerController(); if (!controllerOpt) return; using KernelIdleTimerAction = scheduler::RefreshRateSelector::KernelIdleTimerAction; switch (displayPtr->selectorPtr->getIdleTimerAction()) { case KernelIdleTimerAction::TurnOff: if (displayPtr->isKernelIdleTimerEnabled) { SFTRACE_INT("KernelIdleTimer", 0); updateKernelIdleTimer(displayId, std::chrono::milliseconds::zero(), *controllerOpt); displayPtr->isKernelIdleTimerEnabled = false; } break; case KernelIdleTimerAction::TurnOn: if (!displayPtr->isKernelIdleTimerEnabled) { SFTRACE_INT("KernelIdleTimer", 1); const auto timeout = displayPtr->selectorPtr->getIdleTimerTimeout(); updateKernelIdleTimer(displayId, timeout, *controllerOpt); displayPtr->isKernelIdleTimerEnabled = true; } break; } } void DisplayModeController::updateKernelIdleTimer(PhysicalDisplayId displayId, std::chrono::milliseconds timeout, KernelIdleTimerController controller) { switch (controller) { case KernelIdleTimerController::HwcApi: mComposerPtr->setIdleTimerEnabled(displayId, timeout); break; case KernelIdleTimerController::Sysprop: using namespace std::string_literals; base::SetProperty("graphics.display.kernel_idle_timer.enabled"s, timeout > std::chrono::milliseconds::zero() ? "true"s : "false"s); break; } } auto DisplayModeController::getKernelIdleTimerState(PhysicalDisplayId displayId) const -> KernelIdleTimerState { std::lock_guard lock(mDisplayLock); const auto& displayPtr = FTL_EXPECT(mDisplays.get(displayId).ok_or(KernelIdleTimerState())).get(); const auto desiredModeIdOpt = (std::scoped_lock(displayPtr->desiredModeLock), displayPtr->desiredModeOpt) .transform([](const display::DisplayModeRequest& request) { return request.mode.modePtr->getId(); }); return {desiredModeIdOpt, displayPtr->isKernelIdleTimerEnabled}; } } // namespace android::display services/surfaceflinger/Display/DisplayModeController.h +17 −0 Original line number Diff line number Diff line Loading @@ -97,6 +97,17 @@ public: void setActiveMode(PhysicalDisplayId, DisplayModeId, Fps vsyncRate, Fps renderFps) EXCLUDES(mDisplayLock); void updateKernelIdleTimer(PhysicalDisplayId) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock); struct KernelIdleTimerState { std::optional<DisplayModeId> desiredModeIdOpt = std::nullopt; bool isEnabled = false; }; KernelIdleTimerState getKernelIdleTimerState(PhysicalDisplayId) const REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock); private: struct Display { template <size_t N> Loading @@ -121,6 +132,8 @@ private: DisplayModeRequestOpt pendingModeOpt GUARDED_BY(kMainThreadContext); bool isModeSetPending GUARDED_BY(kMainThreadContext) = false; bool isKernelIdleTimerEnabled GUARDED_BY(kMainThreadContext) = false; }; using DisplayPtr = std::unique_ptr<Display>; Loading @@ -128,6 +141,10 @@ private: void setActiveModeLocked(PhysicalDisplayId, DisplayModeId, Fps vsyncRate, Fps renderFps) REQUIRES(mDisplayLock); using KernelIdleTimerController = scheduler::RefreshRateSelector::KernelIdleTimerController; void updateKernelIdleTimer(PhysicalDisplayId, std::chrono::milliseconds timeout, KernelIdleTimerController) REQUIRES(mDisplayLock); // Set once when initializing the DisplayModeController, which the HWComposer must outlive. HWComposer* mComposerPtr = nullptr; Loading services/surfaceflinger/SurfaceFlinger.cpp +6 −73 Original line number Diff line number Diff line Loading @@ -205,8 +205,6 @@ using ui::Dataspace; using ui::DisplayPrimaries; using ui::RenderIntent; using KernelIdleTimerController = scheduler::RefreshRateSelector::KernelIdleTimerController; namespace hal = android::hardware::graphics::composer::hal; namespace { Loading Loading @@ -374,8 +372,6 @@ const String16 sCaptureBlackoutContent("android.permission.CAPTURE_BLACKOUT_CONT const String16 sInternalSystemWindow("android.permission.INTERNAL_SYSTEM_WINDOW"); const String16 sWakeupSurfaceFlinger("android.permission.WAKEUP_SURFACE_FLINGER"); const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled"; // --------------------------------------------------------------------------- int64_t SurfaceFlinger::dispSyncPresentTimeOffset; bool SurfaceFlinger::useHwcForRgbToYuv; Loading Loading @@ -6932,7 +6928,7 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { // Update the overlay on the main thread to avoid race conditions with // RefreshRateSelector::getActiveMode static_cast<void>(mScheduler->schedule([=, this] { static_cast<void>(mScheduler->schedule([=, this]() FTL_FAKE_GUARD(kMainThreadContext) { const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); if (!display) { ALOGW("%s: default display is null", __func__); Loading @@ -6940,15 +6936,9 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { } if (!display->isRefreshRateOverlayEnabled()) return; const auto desiredModeIdOpt = mDisplayModeController.getDesiredMode(display->getPhysicalId()) .transform([](const display::DisplayModeRequest& request) { return request.mode.modePtr->getId(); }); const bool timerExpired = mKernelIdleTimerEnabled && expired; const auto state = mDisplayModeController.getKernelIdleTimerState(display->getPhysicalId()); if (display->onKernelTimerChanged(desiredModeIdOpt, timerExpired)) { if (display->onKernelTimerChanged(state.desiredModeIdOpt, state.isEnabled && expired)) { mScheduler->scheduleFrame(); } })); Loading @@ -6970,8 +6960,8 @@ void SurfaceFlinger::vrrDisplayIdle(bool idle) { })); } std::pair<std::optional<KernelIdleTimerController>, std::chrono::milliseconds> SurfaceFlinger::getKernelIdleTimerProperties(PhysicalDisplayId displayId) { auto SurfaceFlinger::getKernelIdleTimerProperties(PhysicalDisplayId displayId) -> std::pair<std::optional<KernelIdleTimerController>, std::chrono::milliseconds> { const bool isKernelIdleTimerHwcSupported = getHwComposer().getComposer()->isSupported( android::Hwc2::Composer::OptionalFeature::KernelIdleTimer); const auto timeout = getIdleTimerTimeout(displayId); Loading @@ -6995,63 +6985,6 @@ SurfaceFlinger::getKernelIdleTimerProperties(PhysicalDisplayId displayId) { return {std::nullopt, timeout}; } void SurfaceFlinger::updateKernelIdleTimer(std::chrono::milliseconds timeout, KernelIdleTimerController controller, PhysicalDisplayId displayId) { switch (controller) { case KernelIdleTimerController::HwcApi: { getHwComposer().setIdleTimerEnabled(displayId, timeout); break; } case KernelIdleTimerController::Sysprop: { base::SetProperty(KERNEL_IDLE_TIMER_PROP, timeout > 0ms ? "true" : "false"); break; } } } void SurfaceFlinger::toggleKernelIdleTimer() { using KernelIdleTimerAction = scheduler::RefreshRateSelector::KernelIdleTimerAction; const auto display = getDefaultDisplayDeviceLocked(); if (!display) { ALOGW("%s: default display is null", __func__); return; } // If the support for kernel idle timer is disabled for the active display, // don't do anything. const std::optional<KernelIdleTimerController> kernelIdleTimerController = display->refreshRateSelector().kernelIdleTimerController(); if (!kernelIdleTimerController.has_value()) { return; } const KernelIdleTimerAction action = display->refreshRateSelector().getIdleTimerAction(); switch (action) { case KernelIdleTimerAction::TurnOff: if (mKernelIdleTimerEnabled) { SFTRACE_INT("KernelIdleTimer", 0); std::chrono::milliseconds constexpr kTimerDisabledTimeout = 0ms; updateKernelIdleTimer(kTimerDisabledTimeout, kernelIdleTimerController.value(), display->getPhysicalId()); mKernelIdleTimerEnabled = false; } break; case KernelIdleTimerAction::TurnOn: if (!mKernelIdleTimerEnabled) { SFTRACE_INT("KernelIdleTimer", 1); const std::chrono::milliseconds timeout = display->refreshRateSelector().getIdleTimerTimeout(); updateKernelIdleTimer(timeout, kernelIdleTimerController.value(), display->getPhysicalId()); mKernelIdleTimerEnabled = true; } break; } } // A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope class WindowDisconnector { public: Loading Loading @@ -7938,7 +7871,7 @@ status_t SurfaceFlinger::applyRefreshRateSelectorPolicy( if (const bool isPacesetter = mScheduler->onDisplayModeChanged(displayId, selector.getActiveMode())) { toggleKernelIdleTimer(); mDisplayModeController.updateKernelIdleTimer(displayId); } auto preferredModeOpt = getPreferredDisplayMode(displayId, currentPolicy.defaultMode); Loading services/surfaceflinger/SurfaceFlinger.h +1 −10 Original line number Diff line number Diff line Loading @@ -707,22 +707,13 @@ private: // ICEPowerCallback overrides: void notifyCpuLoadUp() override; // Toggles the kernel idle timer on or off depending the policy decisions around refresh rates. void toggleKernelIdleTimer() REQUIRES(mStateLock); using KernelIdleTimerController = scheduler::RefreshRateSelector::KernelIdleTimerController; // Get the controller and timeout that will help decide how the kernel idle timer will be // configured and what value to use as the timeout. std::pair<std::optional<KernelIdleTimerController>, std::chrono::milliseconds> getKernelIdleTimerProperties(PhysicalDisplayId) REQUIRES(mStateLock); // Updates the kernel idle timer either through HWC or through sysprop // depending on which controller is provided void updateKernelIdleTimer(std::chrono::milliseconds timeoutMs, KernelIdleTimerController, PhysicalDisplayId) REQUIRES(mStateLock); // Keeps track of whether the kernel idle timer is currently enabled, so we don't have to // make calls to sys prop each time. bool mKernelIdleTimerEnabled = false; // Show spinner with refresh rate overlay bool mRefreshRateOverlaySpinner = false; // Show render rate with refresh rate overlay Loading Loading
services/surfaceflinger/Display/DisplayModeController.cpp +61 −0 Original line number Diff line number Diff line Loading @@ -22,7 +22,9 @@ #include "Display/DisplaySnapshot.h" #include "DisplayHardware/HWComposer.h" #include <android-base/properties.h> #include <common/FlagManager.h> #include <common/trace.h> #include <ftl/concat.h> #include <ftl/expected.h> #include <log/log.h> Loading Loading @@ -237,4 +239,63 @@ void DisplayModeController::setActiveModeLocked(PhysicalDisplayId displayId, Dis } } void DisplayModeController::updateKernelIdleTimer(PhysicalDisplayId displayId) { std::lock_guard lock(mDisplayLock); const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get(); const auto controllerOpt = displayPtr->selectorPtr->kernelIdleTimerController(); if (!controllerOpt) return; using KernelIdleTimerAction = scheduler::RefreshRateSelector::KernelIdleTimerAction; switch (displayPtr->selectorPtr->getIdleTimerAction()) { case KernelIdleTimerAction::TurnOff: if (displayPtr->isKernelIdleTimerEnabled) { SFTRACE_INT("KernelIdleTimer", 0); updateKernelIdleTimer(displayId, std::chrono::milliseconds::zero(), *controllerOpt); displayPtr->isKernelIdleTimerEnabled = false; } break; case KernelIdleTimerAction::TurnOn: if (!displayPtr->isKernelIdleTimerEnabled) { SFTRACE_INT("KernelIdleTimer", 1); const auto timeout = displayPtr->selectorPtr->getIdleTimerTimeout(); updateKernelIdleTimer(displayId, timeout, *controllerOpt); displayPtr->isKernelIdleTimerEnabled = true; } break; } } void DisplayModeController::updateKernelIdleTimer(PhysicalDisplayId displayId, std::chrono::milliseconds timeout, KernelIdleTimerController controller) { switch (controller) { case KernelIdleTimerController::HwcApi: mComposerPtr->setIdleTimerEnabled(displayId, timeout); break; case KernelIdleTimerController::Sysprop: using namespace std::string_literals; base::SetProperty("graphics.display.kernel_idle_timer.enabled"s, timeout > std::chrono::milliseconds::zero() ? "true"s : "false"s); break; } } auto DisplayModeController::getKernelIdleTimerState(PhysicalDisplayId displayId) const -> KernelIdleTimerState { std::lock_guard lock(mDisplayLock); const auto& displayPtr = FTL_EXPECT(mDisplays.get(displayId).ok_or(KernelIdleTimerState())).get(); const auto desiredModeIdOpt = (std::scoped_lock(displayPtr->desiredModeLock), displayPtr->desiredModeOpt) .transform([](const display::DisplayModeRequest& request) { return request.mode.modePtr->getId(); }); return {desiredModeIdOpt, displayPtr->isKernelIdleTimerEnabled}; } } // namespace android::display
services/surfaceflinger/Display/DisplayModeController.h +17 −0 Original line number Diff line number Diff line Loading @@ -97,6 +97,17 @@ public: void setActiveMode(PhysicalDisplayId, DisplayModeId, Fps vsyncRate, Fps renderFps) EXCLUDES(mDisplayLock); void updateKernelIdleTimer(PhysicalDisplayId) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock); struct KernelIdleTimerState { std::optional<DisplayModeId> desiredModeIdOpt = std::nullopt; bool isEnabled = false; }; KernelIdleTimerState getKernelIdleTimerState(PhysicalDisplayId) const REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock); private: struct Display { template <size_t N> Loading @@ -121,6 +132,8 @@ private: DisplayModeRequestOpt pendingModeOpt GUARDED_BY(kMainThreadContext); bool isModeSetPending GUARDED_BY(kMainThreadContext) = false; bool isKernelIdleTimerEnabled GUARDED_BY(kMainThreadContext) = false; }; using DisplayPtr = std::unique_ptr<Display>; Loading @@ -128,6 +141,10 @@ private: void setActiveModeLocked(PhysicalDisplayId, DisplayModeId, Fps vsyncRate, Fps renderFps) REQUIRES(mDisplayLock); using KernelIdleTimerController = scheduler::RefreshRateSelector::KernelIdleTimerController; void updateKernelIdleTimer(PhysicalDisplayId, std::chrono::milliseconds timeout, KernelIdleTimerController) REQUIRES(mDisplayLock); // Set once when initializing the DisplayModeController, which the HWComposer must outlive. HWComposer* mComposerPtr = nullptr; Loading
services/surfaceflinger/SurfaceFlinger.cpp +6 −73 Original line number Diff line number Diff line Loading @@ -205,8 +205,6 @@ using ui::Dataspace; using ui::DisplayPrimaries; using ui::RenderIntent; using KernelIdleTimerController = scheduler::RefreshRateSelector::KernelIdleTimerController; namespace hal = android::hardware::graphics::composer::hal; namespace { Loading Loading @@ -374,8 +372,6 @@ const String16 sCaptureBlackoutContent("android.permission.CAPTURE_BLACKOUT_CONT const String16 sInternalSystemWindow("android.permission.INTERNAL_SYSTEM_WINDOW"); const String16 sWakeupSurfaceFlinger("android.permission.WAKEUP_SURFACE_FLINGER"); const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled"; // --------------------------------------------------------------------------- int64_t SurfaceFlinger::dispSyncPresentTimeOffset; bool SurfaceFlinger::useHwcForRgbToYuv; Loading Loading @@ -6932,7 +6928,7 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { // Update the overlay on the main thread to avoid race conditions with // RefreshRateSelector::getActiveMode static_cast<void>(mScheduler->schedule([=, this] { static_cast<void>(mScheduler->schedule([=, this]() FTL_FAKE_GUARD(kMainThreadContext) { const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); if (!display) { ALOGW("%s: default display is null", __func__); Loading @@ -6940,15 +6936,9 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { } if (!display->isRefreshRateOverlayEnabled()) return; const auto desiredModeIdOpt = mDisplayModeController.getDesiredMode(display->getPhysicalId()) .transform([](const display::DisplayModeRequest& request) { return request.mode.modePtr->getId(); }); const bool timerExpired = mKernelIdleTimerEnabled && expired; const auto state = mDisplayModeController.getKernelIdleTimerState(display->getPhysicalId()); if (display->onKernelTimerChanged(desiredModeIdOpt, timerExpired)) { if (display->onKernelTimerChanged(state.desiredModeIdOpt, state.isEnabled && expired)) { mScheduler->scheduleFrame(); } })); Loading @@ -6970,8 +6960,8 @@ void SurfaceFlinger::vrrDisplayIdle(bool idle) { })); } std::pair<std::optional<KernelIdleTimerController>, std::chrono::milliseconds> SurfaceFlinger::getKernelIdleTimerProperties(PhysicalDisplayId displayId) { auto SurfaceFlinger::getKernelIdleTimerProperties(PhysicalDisplayId displayId) -> std::pair<std::optional<KernelIdleTimerController>, std::chrono::milliseconds> { const bool isKernelIdleTimerHwcSupported = getHwComposer().getComposer()->isSupported( android::Hwc2::Composer::OptionalFeature::KernelIdleTimer); const auto timeout = getIdleTimerTimeout(displayId); Loading @@ -6995,63 +6985,6 @@ SurfaceFlinger::getKernelIdleTimerProperties(PhysicalDisplayId displayId) { return {std::nullopt, timeout}; } void SurfaceFlinger::updateKernelIdleTimer(std::chrono::milliseconds timeout, KernelIdleTimerController controller, PhysicalDisplayId displayId) { switch (controller) { case KernelIdleTimerController::HwcApi: { getHwComposer().setIdleTimerEnabled(displayId, timeout); break; } case KernelIdleTimerController::Sysprop: { base::SetProperty(KERNEL_IDLE_TIMER_PROP, timeout > 0ms ? "true" : "false"); break; } } } void SurfaceFlinger::toggleKernelIdleTimer() { using KernelIdleTimerAction = scheduler::RefreshRateSelector::KernelIdleTimerAction; const auto display = getDefaultDisplayDeviceLocked(); if (!display) { ALOGW("%s: default display is null", __func__); return; } // If the support for kernel idle timer is disabled for the active display, // don't do anything. const std::optional<KernelIdleTimerController> kernelIdleTimerController = display->refreshRateSelector().kernelIdleTimerController(); if (!kernelIdleTimerController.has_value()) { return; } const KernelIdleTimerAction action = display->refreshRateSelector().getIdleTimerAction(); switch (action) { case KernelIdleTimerAction::TurnOff: if (mKernelIdleTimerEnabled) { SFTRACE_INT("KernelIdleTimer", 0); std::chrono::milliseconds constexpr kTimerDisabledTimeout = 0ms; updateKernelIdleTimer(kTimerDisabledTimeout, kernelIdleTimerController.value(), display->getPhysicalId()); mKernelIdleTimerEnabled = false; } break; case KernelIdleTimerAction::TurnOn: if (!mKernelIdleTimerEnabled) { SFTRACE_INT("KernelIdleTimer", 1); const std::chrono::milliseconds timeout = display->refreshRateSelector().getIdleTimerTimeout(); updateKernelIdleTimer(timeout, kernelIdleTimerController.value(), display->getPhysicalId()); mKernelIdleTimerEnabled = true; } break; } } // A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope class WindowDisconnector { public: Loading Loading @@ -7938,7 +7871,7 @@ status_t SurfaceFlinger::applyRefreshRateSelectorPolicy( if (const bool isPacesetter = mScheduler->onDisplayModeChanged(displayId, selector.getActiveMode())) { toggleKernelIdleTimer(); mDisplayModeController.updateKernelIdleTimer(displayId); } auto preferredModeOpt = getPreferredDisplayMode(displayId, currentPolicy.defaultMode); Loading
services/surfaceflinger/SurfaceFlinger.h +1 −10 Original line number Diff line number Diff line Loading @@ -707,22 +707,13 @@ private: // ICEPowerCallback overrides: void notifyCpuLoadUp() override; // Toggles the kernel idle timer on or off depending the policy decisions around refresh rates. void toggleKernelIdleTimer() REQUIRES(mStateLock); using KernelIdleTimerController = scheduler::RefreshRateSelector::KernelIdleTimerController; // Get the controller and timeout that will help decide how the kernel idle timer will be // configured and what value to use as the timeout. std::pair<std::optional<KernelIdleTimerController>, std::chrono::milliseconds> getKernelIdleTimerProperties(PhysicalDisplayId) REQUIRES(mStateLock); // Updates the kernel idle timer either through HWC or through sysprop // depending on which controller is provided void updateKernelIdleTimer(std::chrono::milliseconds timeoutMs, KernelIdleTimerController, PhysicalDisplayId) REQUIRES(mStateLock); // Keeps track of whether the kernel idle timer is currently enabled, so we don't have to // make calls to sys prop each time. bool mKernelIdleTimerEnabled = false; // Show spinner with refresh rate overlay bool mRefreshRateOverlaySpinner = false; // Show render rate with refresh rate overlay Loading