@@ -1366,7 +1366,8 @@ void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& desiredMode) {
13661366 const auto selectorPtr = mDisplayModeController .selectorPtrFor (displayId);
13671367 if (!selectorPtr) break ;
13681368
1369- const Fps renderRate = selectorPtr->getActiveMode ().fps ;
1369+ const auto activeMode = selectorPtr->getActiveMode ();
1370+ const Fps renderRate = activeMode.fps ;
13701371
13711372 // DisplayModeController::setDesiredMode updated the render rate, so inform Scheduler.
13721373 mScheduler ->setRenderRate (displayId, renderRate, true /* applyImmediately */ );
@@ -1385,6 +1386,15 @@ void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& desiredMode) {
13851386
13861387 mScheduler ->updatePhaseConfiguration (displayId, mode.fps );
13871388 mScheduler ->setModeChangePending (true );
1389+
1390+ // The mode set to switch resolution is not initiated until the display transaction that
1391+ // resizes the display. DM sends this transaction in response to a mode change event, so
1392+ // emit the event now, not when finalizing the mode change as for a refresh rate switch.
1393+ if (FlagManager::getInstance ().synced_resolution_switch () &&
1394+ !mode.matchesResolution (activeMode)) {
1395+ mScheduler ->onDisplayModeChanged (displayId, mode,
1396+ /* clearContentRequirements*/ true );
1397+ }
13881398 break ;
13891399 }
13901400 case DesiredModeAction::InitiateRenderRateSwitch:
@@ -1463,27 +1473,34 @@ bool SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) {
14631473 }
14641474
14651475 const auto & activeMode = pendingModeOpt->mode ;
1466-
1467- if (const auto oldResolution =
1468- mDisplayModeController .getActiveMode (displayId).modePtr ->getResolution ();
1469- oldResolution != activeMode.modePtr ->getResolution ()) {
1470- auto & state = mCurrentState .displays .editValueFor (getPhysicalDisplayTokenLocked (displayId));
1471- // We need to generate new sequenceId in order to recreate the display (and this
1472- // way the framebuffer).
1473- state.sequenceId = DisplayDeviceState{}.sequenceId ;
1474- state.physical ->activeMode = activeMode.modePtr .get ();
1475- processDisplayChangesLocked ();
1476-
1477- // The DisplayDevice has been destroyed, so abort the commit for the now dead FrameTargeter.
1478- return false ;
1476+ const bool resolutionMatch = !FlagManager::getInstance ().synced_resolution_switch () ||
1477+ activeMode.matchesResolution (mDisplayModeController .getActiveMode (displayId));
1478+
1479+ if (!FlagManager::getInstance ().synced_resolution_switch ()) {
1480+ if (const auto oldResolution =
1481+ mDisplayModeController .getActiveMode (displayId).modePtr ->getResolution ();
1482+ oldResolution != activeMode.modePtr ->getResolution ()) {
1483+ auto & state =
1484+ mCurrentState .displays .editValueFor (getPhysicalDisplayTokenLocked (displayId));
1485+ // We need to generate new sequenceId in order to recreate the display (and this
1486+ // way the framebuffer).
1487+ state.sequenceId = DisplayDeviceState{}.sequenceId ;
1488+ state.physical ->activeMode = activeMode.modePtr .get ();
1489+ processDisplayChangesLocked ();
1490+
1491+ // The DisplayDevice has been destroyed, so abort the commit for the now dead
1492+ // FrameTargeter.
1493+ return false ;
1494+ }
14791495 }
14801496
14811497 mDisplayModeController .finalizeModeChange (displayId, activeMode.modePtr ->getId (),
14821498 activeMode.modePtr ->getVsyncRate (), activeMode.fps );
14831499
14841500 mScheduler ->updatePhaseConfiguration (displayId, activeMode.fps );
14851501
1486- if (pendingModeOpt->emitEvent ) {
1502+ // Skip for resolution changes, since the event was already emitted on setting the desired mode.
1503+ if (resolutionMatch && pendingModeOpt->emitEvent ) {
14871504 mScheduler ->onDisplayModeChanged (displayId, activeMode, /* clearContentRequirements*/ true );
14881505 }
14891506
@@ -1535,8 +1552,9 @@ void SurfaceFlinger::initiateDisplayModeChanges() {
15351552 to_string (displayModePtrOpt->get ()->getVsyncRate ()).c_str (),
15361553 to_string (displayId).c_str ());
15371554
1538- if ((!FlagManager::getInstance ().connected_display () || !desiredModeOpt->force ) &&
1539- mDisplayModeController .getActiveMode (displayId) == desiredModeOpt->mode ) {
1555+ const auto activeMode = mDisplayModeController .getActiveMode (displayId);
1556+
1557+ if (!desiredModeOpt->force && desiredModeOpt->mode == activeMode) {
15401558 applyActiveMode (displayId);
15411559 continue ;
15421560 }
@@ -1557,6 +1575,15 @@ void SurfaceFlinger::initiateDisplayModeChanges() {
15571575 constraints.seamlessRequired = false ;
15581576 hal::VsyncPeriodChangeTimeline outTimeline;
15591577
1578+ // When initiating a resolution change, wait until the commit that resizes the display.
1579+ if (FlagManager::getInstance ().synced_resolution_switch () &&
1580+ !activeMode.matchesResolution (desiredModeOpt->mode )) {
1581+ const auto display = getDisplayDeviceLocked (displayId);
1582+ if (display->getSize () != desiredModeOpt->mode .modePtr ->getResolution ()) {
1583+ continue ;
1584+ }
1585+ }
1586+
15601587 const auto error =
15611588 mDisplayModeController .initiateModeChange (displayId, std::move (*desiredModeOpt),
15621589 constraints, outTimeline);
@@ -4096,6 +4123,35 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken,
40964123 if (currentState.flags != drawingState.flags ) {
40974124 display->setFlags (currentState.flags );
40984125 }
4126+
4127+ const auto updateDisplaySize = [&]() {
4128+ if (currentState.width != drawingState.width ||
4129+ currentState.height != drawingState.height ) {
4130+ const ui::Size resolution = ui::Size (currentState.width , currentState.height );
4131+
4132+ // Resize the framebuffer. For a virtual display, always do so. For a physical
4133+ // display, only do so if it has a pending modeset for the matching resolution.
4134+ if (!currentState.physical ||
4135+ (FlagManager::getInstance ().synced_resolution_switch () &&
4136+ mDisplayModeController .getDesiredMode (display->getPhysicalId ())
4137+ .transform ([resolution](const auto & request) {
4138+ return resolution == request.mode .modePtr ->getResolution ();
4139+ })
4140+ .value_or (false ))) {
4141+ display->setDisplaySize (resolution);
4142+ }
4143+
4144+ if (display->getId () == mActiveDisplayId ) {
4145+ onActiveDisplaySizeChanged (*display);
4146+ }
4147+ }
4148+ };
4149+
4150+ if (FlagManager::getInstance ().synced_resolution_switch ()) {
4151+ // Update display size first, as display projection below depends on it.
4152+ updateDisplaySize ();
4153+ }
4154+
40994155 if ((currentState.orientation != drawingState.orientation ) ||
41004156 (currentState.layerStackSpaceRect != drawingState.layerStackSpaceRect ) ||
41014157 (currentState.orientedDisplaySpaceRect != drawingState.orientedDisplaySpaceRect )) {
@@ -4107,13 +4163,9 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken,
41074163 ui::Transform::toRotationFlags (display->getOrientation ());
41084164 }
41094165 }
4110- if (currentState.width != drawingState.width ||
4111- currentState.height != drawingState.height ) {
4112- display->setDisplaySize (currentState.width , currentState.height );
41134166
4114- if (display->getId () == mActiveDisplayId ) {
4115- onActiveDisplaySizeChanged (*display);
4116- }
4167+ if (!FlagManager::getInstance ().synced_resolution_switch ()) {
4168+ updateDisplaySize ();
41174169 }
41184170 }
41194171}
0 commit comments