@@ -1363,7 +1363,8 @@ void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& desiredMode) {
13631363 const auto selectorPtr = mDisplayModeController .selectorPtrFor (displayId);
13641364 if (!selectorPtr) break ;
13651365
1366- const Fps renderRate = selectorPtr->getActiveMode ().fps ;
1366+ const auto activeMode = selectorPtr->getActiveMode ();
1367+ const Fps renderRate = activeMode.fps ;
13671368
13681369 // DisplayModeController::setDesiredMode updated the render rate, so inform Scheduler.
13691370 mScheduler ->setRenderRate (displayId, renderRate, true /* applyImmediately */ );
@@ -1382,6 +1383,15 @@ void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& desiredMode) {
13821383
13831384 mScheduler ->updatePhaseConfiguration (displayId, mode.fps );
13841385 mScheduler ->setModeChangePending (true );
1386+
1387+ // The mode set to switch resolution is not initiated until the display transaction that
1388+ // resizes the display. DM sends this transaction in response to a mode change event, so
1389+ // emit the event now, not when finalizing the mode change as for a refresh rate switch.
1390+ if (FlagManager::getInstance ().synced_resolution_switch () &&
1391+ !mode.matchesResolution (activeMode)) {
1392+ mScheduler ->onDisplayModeChanged (displayId, mode,
1393+ /* clearContentRequirements*/ true );
1394+ }
13851395 break ;
13861396 }
13871397 case DesiredModeAction::InitiateRenderRateSwitch:
@@ -1460,27 +1470,34 @@ bool SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) {
14601470 }
14611471
14621472 const auto & activeMode = pendingModeOpt->mode ;
1463-
1464- if (const auto oldResolution =
1465- mDisplayModeController .getActiveMode (displayId).modePtr ->getResolution ();
1466- oldResolution != activeMode.modePtr ->getResolution ()) {
1467- auto & state = mCurrentState .displays .editValueFor (getPhysicalDisplayTokenLocked (displayId));
1468- // We need to generate new sequenceId in order to recreate the display (and this
1469- // way the framebuffer).
1470- state.sequenceId = DisplayDeviceState{}.sequenceId ;
1471- state.physical ->activeMode = activeMode.modePtr .get ();
1472- processDisplayChangesLocked ();
1473-
1474- // The DisplayDevice has been destroyed, so abort the commit for the now dead FrameTargeter.
1475- return false ;
1473+ const bool resolutionMatch = !FlagManager::getInstance ().synced_resolution_switch () ||
1474+ activeMode.matchesResolution (mDisplayModeController .getActiveMode (displayId));
1475+
1476+ if (!FlagManager::getInstance ().synced_resolution_switch ()) {
1477+ if (const auto oldResolution =
1478+ mDisplayModeController .getActiveMode (displayId).modePtr ->getResolution ();
1479+ oldResolution != activeMode.modePtr ->getResolution ()) {
1480+ auto & state =
1481+ mCurrentState .displays .editValueFor (getPhysicalDisplayTokenLocked (displayId));
1482+ // We need to generate new sequenceId in order to recreate the display (and this
1483+ // way the framebuffer).
1484+ state.sequenceId = DisplayDeviceState{}.sequenceId ;
1485+ state.physical ->activeMode = activeMode.modePtr .get ();
1486+ processDisplayChangesLocked ();
1487+
1488+ // The DisplayDevice has been destroyed, so abort the commit for the now dead
1489+ // FrameTargeter.
1490+ return false ;
1491+ }
14761492 }
14771493
14781494 mDisplayModeController .finalizeModeChange (displayId, activeMode.modePtr ->getId (),
14791495 activeMode.modePtr ->getVsyncRate (), activeMode.fps );
14801496
14811497 mScheduler ->updatePhaseConfiguration (displayId, activeMode.fps );
14821498
1483- if (pendingModeOpt->emitEvent ) {
1499+ // Skip for resolution changes, since the event was already emitted on setting the desired mode.
1500+ if (resolutionMatch && pendingModeOpt->emitEvent ) {
14841501 mScheduler ->onDisplayModeChanged (displayId, activeMode, /* clearContentRequirements*/ true );
14851502 }
14861503
@@ -1532,8 +1549,9 @@ void SurfaceFlinger::initiateDisplayModeChanges() {
15321549 to_string (displayModePtrOpt->get ()->getVsyncRate ()).c_str (),
15331550 to_string (displayId).c_str ());
15341551
1535- if ((!FlagManager::getInstance ().connected_display () || !desiredModeOpt->force ) &&
1536- mDisplayModeController .getActiveMode (displayId) == desiredModeOpt->mode ) {
1552+ const auto activeMode = mDisplayModeController .getActiveMode (displayId);
1553+
1554+ if (!desiredModeOpt->force && desiredModeOpt->mode == activeMode) {
15371555 applyActiveMode (displayId);
15381556 continue ;
15391557 }
@@ -1554,6 +1572,15 @@ void SurfaceFlinger::initiateDisplayModeChanges() {
15541572 constraints.seamlessRequired = false ;
15551573 hal::VsyncPeriodChangeTimeline outTimeline;
15561574
1575+ // When initiating a resolution change, wait until the commit that resizes the display.
1576+ if (FlagManager::getInstance ().synced_resolution_switch () &&
1577+ !activeMode.matchesResolution (desiredModeOpt->mode )) {
1578+ const auto display = getDisplayDeviceLocked (displayId);
1579+ if (display->getSize () != desiredModeOpt->mode .modePtr ->getResolution ()) {
1580+ continue ;
1581+ }
1582+ }
1583+
15571584 const auto error =
15581585 mDisplayModeController .initiateModeChange (displayId, std::move (*desiredModeOpt),
15591586 constraints, outTimeline);
@@ -4124,6 +4151,35 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken,
41244151 if (currentState.flags != drawingState.flags ) {
41254152 display->setFlags (currentState.flags );
41264153 }
4154+
4155+ const auto updateDisplaySize = [&]() {
4156+ if (currentState.width != drawingState.width ||
4157+ currentState.height != drawingState.height ) {
4158+ const ui::Size resolution = ui::Size (currentState.width , currentState.height );
4159+
4160+ // Resize the framebuffer. For a virtual display, always do so. For a physical
4161+ // display, only do so if it has a pending modeset for the matching resolution.
4162+ if (!currentState.physical ||
4163+ (FlagManager::getInstance ().synced_resolution_switch () &&
4164+ mDisplayModeController .getDesiredMode (display->getPhysicalId ())
4165+ .transform ([resolution](const auto & request) {
4166+ return resolution == request.mode .modePtr ->getResolution ();
4167+ })
4168+ .value_or (false ))) {
4169+ display->setDisplaySize (resolution);
4170+ }
4171+
4172+ if (display->getId () == mActiveDisplayId ) {
4173+ onActiveDisplaySizeChanged (*display);
4174+ }
4175+ }
4176+ };
4177+
4178+ if (FlagManager::getInstance ().synced_resolution_switch ()) {
4179+ // Update display size first, as display projection below depends on it.
4180+ updateDisplaySize ();
4181+ }
4182+
41274183 if ((currentState.orientation != drawingState.orientation ) ||
41284184 (currentState.layerStackSpaceRect != drawingState.layerStackSpaceRect ) ||
41294185 (currentState.orientedDisplaySpaceRect != drawingState.orientedDisplaySpaceRect )) {
@@ -4135,13 +4191,9 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken,
41354191 ui::Transform::toRotationFlags (display->getOrientation ());
41364192 }
41374193 }
4138- if (currentState.width != drawingState.width ||
4139- currentState.height != drawingState.height ) {
4140- display->setDisplaySize (currentState.width , currentState.height );
41414194
4142- if (display->getId () == mActiveDisplayId ) {
4143- onActiveDisplaySizeChanged (*display);
4144- }
4195+ if (!FlagManager::getInstance ().synced_resolution_switch ()) {
4196+ updateDisplaySize ();
41454197 }
41464198 }
41474199}
0 commit comments