SF: Isolate modesetting in DisplayModeController
Move the per-display state machine for modesetting from DisplayDevice to
DMC. In lieu of mStateLock, protect display lookup from multiple threads
using a mutex internal to DMC, which fixes the following deadlock:
OneShotTimer::loop
SF::requestDisplayModes
mStateLock
SF::commit
mStateLock
SF::processDisplayChangesLocked (hotplug or resolution change)
Scheduler::demotePacesetterDisplay
OneShotTimer::stop
A notable change is that {initiate,finalize}DisplayModeChange(s) are no
longer called under mStateLock, thanks to DMC's granular, internal lock.
finalizeDisplayModeChange still locks mStateLock for resolution changes.
Add an ActiveModeListener to DMC and register a callback in SF to update
the refresh rate overlay, which still lives in DisplayDevice for now.
Fixes: 329450361
Bug: 241285876
Test: DisplayModeControllerTest
Test: libsurfaceflinger_unittest
Change-Id: I30ec756f134d2d67a70ac8797008dc792eac035e
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 8c72a7d..007383b 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -191,6 +191,8 @@
void setupComposer(std::unique_ptr<Hwc2::Composer> composer) {
mFlinger->mCompositionEngine->setHwComposer(
std::make_unique<impl::HWComposer>(std::move(composer)));
+ mFlinger->mDisplayModeController.setHwComposer(
+ &mFlinger->mCompositionEngine->getHwComposer());
}
void setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor> powerAdvisor) {
@@ -1055,7 +1057,6 @@
auto& modes = mDisplayModes;
auto& activeModeId = mActiveModeId;
- std::optional<Fps> refreshRateOpt;
DisplayDeviceState state;
state.isSecure = mCreationArgs.isSecure;
@@ -1093,7 +1094,9 @@
const auto activeModeOpt = modes.get(activeModeId);
LOG_ALWAYS_FATAL_IF(!activeModeOpt);
- refreshRateOpt = activeModeOpt->get()->getPeakFps();
+
+ // Save a copy for use after `modes` is consumed.
+ const Fps refreshRate = activeModeOpt->get()->getPeakFps();
state.physical = {.id = *physicalId,
.hwcDisplayId = *mHwcDisplayId,
@@ -1109,6 +1112,9 @@
.registerDisplay(*physicalId, it->second.snapshot(),
mCreationArgs.refreshRateSelector);
+ mFlinger.mutableDisplayModeController().setActiveMode(*physicalId, activeModeId,
+ refreshRate, refreshRate);
+
if (mFlinger.scheduler() && mSchedulerRegistration) {
mFlinger.scheduler()->registerDisplay(*physicalId,
mCreationArgs.refreshRateSelector,
@@ -1120,10 +1126,6 @@
sp<DisplayDevice> display = sp<DisplayDevice>::make(mCreationArgs);
mFlinger.mutableDisplays().emplace_or_replace(mDisplayToken, display);
- if (refreshRateOpt) {
- display->setActiveMode(activeModeId, *refreshRateOpt, *refreshRateOpt);
- }
-
mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);