diff options
author | 2025-02-12 11:30:57 -0800 | |
---|---|---|
committer | 2025-02-12 11:30:57 -0800 | |
commit | e07d8df19ae4ded31d1ade217d757da2b865e5da (patch) | |
tree | a34c1666b19f2129a634f90084d59fd49871c56c | |
parent | 06b6e6bbe48b67ec86765fd2a2d6b6e507692af1 (diff) | |
parent | 251e612d09ee1762dede0a873d5bb4c2c8d354d7 (diff) |
Merge "SF: Let DM resize framebuffer on resolution change" into main
-rw-r--r-- | libs/gui/include/gui/LayerState.h | 12 | ||||
-rw-r--r-- | services/surfaceflinger/Display/DisplayModeRequest.h | 3 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayDevice.cpp | 4 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayDevice.h | 2 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/include/scheduler/FrameRateMode.h | 4 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 98 | ||||
-rw-r--r-- | services/surfaceflinger/common/FlagManager.cpp | 2 | ||||
-rw-r--r-- | services/surfaceflinger/common/include/common/FlagManager.h | 1 | ||||
-rw-r--r-- | services/surfaceflinger/surfaceflinger_flags_new.aconfig | 7 |
9 files changed, 102 insertions, 31 deletions
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index d04b8618f7..c2680a42dc 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -502,12 +502,18 @@ struct DisplayState { Rect layerStackSpaceRect = Rect::EMPTY_RECT; Rect orientedDisplaySpaceRect = Rect::EMPTY_RECT; - // Exclusive to virtual displays: The sink surface into which the virtual display is rendered, - // and an optional resolution that overrides its default dimensions. - sp<IGraphicBufferProducer> surface; + // For physical displays, this is the resolution, which must match the active display mode. To + // change the resolution, the client must first call SurfaceControl.setDesiredDisplayModeSpecs + // with the new DesiredDisplayModeSpecs#defaultMode, then commit the matching width and height. + // + // For virtual displays, this is an optional resolution that overrides its default dimensions. + // uint32_t width = 0; uint32_t height = 0; + // For virtual displays, this is the sink surface into which the virtual display is rendered. + sp<IGraphicBufferProducer> surface; + status_t write(Parcel& output) const; status_t read(const Parcel& input); }; diff --git a/services/surfaceflinger/Display/DisplayModeRequest.h b/services/surfaceflinger/Display/DisplayModeRequest.h index ec3ec526a1..2e9dc1e34e 100644 --- a/services/surfaceflinger/Display/DisplayModeRequest.h +++ b/services/surfaceflinger/Display/DisplayModeRequest.h @@ -26,7 +26,8 @@ namespace android::display { struct DisplayModeRequest { scheduler::FrameRateMode mode; - // Whether to emit DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE. + // Whether to emit DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE for a change in refresh rate + // or render rate. Ignored for resolution changes, which always emit the event. bool emitEvent = false; // Whether to force the request to be applied, even if the mode is unchanged. diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index c743ea2ff4..e8b09b043e 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -223,9 +223,7 @@ void DisplayDevice::setFlags(uint32_t flags) { mFlags = flags; } -void DisplayDevice::setDisplaySize(int width, int height) { - LOG_FATAL_IF(!isVirtual(), "Changing the display size is supported only for virtual displays."); - const auto size = ui::Size(width, height); +void DisplayDevice::setDisplaySize(ui::Size size) { mCompositionDisplay->setDisplaySize(size); if (mRefreshRateOverlay) { mRefreshRateOverlay->setViewport(size); diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 23b36375ce..b5a543a7c1 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -98,7 +98,7 @@ public: ui::Size getSize() const { return {getWidth(), getHeight()}; } void setLayerFilter(ui::LayerFilter); - void setDisplaySize(int width, int height); + void setDisplaySize(ui::Size); void setProjection(ui::Rotation orientation, Rect viewport, Rect frame); void stageBrightness(float brightness) REQUIRES(kMainThreadContext); void persistBrightness(bool needsComposite) REQUIRES(kMainThreadContext); diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameRateMode.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameRateMode.h index f2be316452..4dd3ab6a88 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/FrameRateMode.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameRateMode.h @@ -33,6 +33,10 @@ struct FrameRateMode { } bool operator!=(const FrameRateMode& other) const { return !(*this == other); } + + bool matchesResolution(const FrameRateMode& other) const { + return modePtr->getResolution() == other.modePtr->getResolution(); + } }; inline std::string to_string(const FrameRateMode& mode) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ed3c75e74a..f3db4c5864 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1363,7 +1363,8 @@ void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& desiredMode) { const auto selectorPtr = mDisplayModeController.selectorPtrFor(displayId); if (!selectorPtr) break; - const Fps renderRate = selectorPtr->getActiveMode().fps; + const auto activeMode = selectorPtr->getActiveMode(); + const Fps renderRate = activeMode.fps; // DisplayModeController::setDesiredMode updated the render rate, so inform Scheduler. mScheduler->setRenderRate(displayId, renderRate, true /* applyImmediately */); @@ -1382,6 +1383,15 @@ void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& desiredMode) { mScheduler->updatePhaseConfiguration(displayId, mode.fps); mScheduler->setModeChangePending(true); + + // The mode set to switch resolution is not initiated until the display transaction that + // resizes the display. DM sends this transaction in response to a mode change event, so + // emit the event now, not when finalizing the mode change as for a refresh rate switch. + if (FlagManager::getInstance().synced_resolution_switch() && + !mode.matchesResolution(activeMode)) { + mScheduler->onDisplayModeChanged(displayId, mode, + /*clearContentRequirements*/ true); + } break; } case DesiredModeAction::InitiateRenderRateSwitch: @@ -1460,19 +1470,25 @@ bool SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) { } const auto& activeMode = pendingModeOpt->mode; - - if (const auto oldResolution = - mDisplayModeController.getActiveMode(displayId).modePtr->getResolution(); - oldResolution != activeMode.modePtr->getResolution()) { - auto& state = mCurrentState.displays.editValueFor(getPhysicalDisplayTokenLocked(displayId)); - // We need to generate new sequenceId in order to recreate the display (and this - // way the framebuffer). - state.sequenceId = DisplayDeviceState{}.sequenceId; - state.physical->activeMode = activeMode.modePtr.get(); - processDisplayChangesLocked(); - - // The DisplayDevice has been destroyed, so abort the commit for the now dead FrameTargeter. - return false; + const bool resolutionMatch = !FlagManager::getInstance().synced_resolution_switch() || + activeMode.matchesResolution(mDisplayModeController.getActiveMode(displayId)); + + if (!FlagManager::getInstance().synced_resolution_switch()) { + if (const auto oldResolution = + mDisplayModeController.getActiveMode(displayId).modePtr->getResolution(); + oldResolution != activeMode.modePtr->getResolution()) { + auto& state = + mCurrentState.displays.editValueFor(getPhysicalDisplayTokenLocked(displayId)); + // We need to generate new sequenceId in order to recreate the display (and this + // way the framebuffer). + state.sequenceId = DisplayDeviceState{}.sequenceId; + state.physical->activeMode = activeMode.modePtr.get(); + processDisplayChangesLocked(); + + // The DisplayDevice has been destroyed, so abort the commit for the now dead + // FrameTargeter. + return false; + } } mDisplayModeController.finalizeModeChange(displayId, activeMode.modePtr->getId(), @@ -1480,7 +1496,8 @@ bool SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) { mScheduler->updatePhaseConfiguration(displayId, activeMode.fps); - if (pendingModeOpt->emitEvent) { + // Skip for resolution changes, since the event was already emitted on setting the desired mode. + if (resolutionMatch && pendingModeOpt->emitEvent) { mScheduler->onDisplayModeChanged(displayId, activeMode, /*clearContentRequirements*/ true); } @@ -1532,8 +1549,9 @@ void SurfaceFlinger::initiateDisplayModeChanges() { to_string(displayModePtrOpt->get()->getVsyncRate()).c_str(), to_string(displayId).c_str()); - if ((!FlagManager::getInstance().connected_display() || !desiredModeOpt->force) && - mDisplayModeController.getActiveMode(displayId) == desiredModeOpt->mode) { + const auto activeMode = mDisplayModeController.getActiveMode(displayId); + + if (!desiredModeOpt->force && desiredModeOpt->mode == activeMode) { applyActiveMode(displayId); continue; } @@ -1554,6 +1572,15 @@ void SurfaceFlinger::initiateDisplayModeChanges() { constraints.seamlessRequired = false; hal::VsyncPeriodChangeTimeline outTimeline; + // When initiating a resolution change, wait until the commit that resizes the display. + if (FlagManager::getInstance().synced_resolution_switch() && + !activeMode.matchesResolution(desiredModeOpt->mode)) { + const auto display = getDisplayDeviceLocked(displayId); + if (display->getSize() != desiredModeOpt->mode.modePtr->getResolution()) { + continue; + } + } + const auto error = mDisplayModeController.initiateModeChange(displayId, std::move(*desiredModeOpt), constraints, outTimeline); @@ -4124,6 +4151,35 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, if (currentState.flags != drawingState.flags) { display->setFlags(currentState.flags); } + + const auto updateDisplaySize = [&]() { + if (currentState.width != drawingState.width || + currentState.height != drawingState.height) { + const ui::Size resolution = ui::Size(currentState.width, currentState.height); + + // Resize the framebuffer. For a virtual display, always do so. For a physical + // display, only do so if it has a pending modeset for the matching resolution. + if (!currentState.physical || + (FlagManager::getInstance().synced_resolution_switch() && + mDisplayModeController.getDesiredMode(display->getPhysicalId()) + .transform([resolution](const auto& request) { + return resolution == request.mode.modePtr->getResolution(); + }) + .value_or(false))) { + display->setDisplaySize(resolution); + } + + if (display->getId() == mActiveDisplayId) { + onActiveDisplaySizeChanged(*display); + } + } + }; + + if (FlagManager::getInstance().synced_resolution_switch()) { + // Update display size first, as display projection below depends on it. + updateDisplaySize(); + } + if ((currentState.orientation != drawingState.orientation) || (currentState.layerStackSpaceRect != drawingState.layerStackSpaceRect) || (currentState.orientedDisplaySpaceRect != drawingState.orientedDisplaySpaceRect)) { @@ -4135,13 +4191,9 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, ui::Transform::toRotationFlags(display->getOrientation()); } } - if (currentState.width != drawingState.width || - currentState.height != drawingState.height) { - display->setDisplaySize(currentState.width, currentState.height); - if (display->getId() == mActiveDisplayId) { - onActiveDisplaySizeChanged(*display); - } + if (!FlagManager::getInstance().synced_resolution_switch()) { + updateDisplaySize(); } } } diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp index b1552e6240..f9aba9fe10 100644 --- a/services/surfaceflinger/common/FlagManager.cpp +++ b/services/surfaceflinger/common/FlagManager.cpp @@ -171,6 +171,7 @@ void FlagManager::dump(std::string& result) const { DUMP_ACONFIG_FLAG(restore_blur_step); DUMP_ACONFIG_FLAG(skip_invisible_windows_in_input); DUMP_ACONFIG_FLAG(stable_edid_ids); + DUMP_ACONFIG_FLAG(synced_resolution_switch); DUMP_ACONFIG_FLAG(trace_frame_rate_override); DUMP_ACONFIG_FLAG(true_hdr_screenshots); DUMP_ACONFIG_FLAG(use_known_refresh_rate_for_fps_consistency); @@ -295,6 +296,7 @@ FLAG_MANAGER_ACONFIG_FLAG(skip_invisible_windows_in_input, ""); FLAG_MANAGER_ACONFIG_FLAG(begone_bright_hlg, "debug.sf.begone_bright_hlg"); FLAG_MANAGER_ACONFIG_FLAG(window_blur_kawase2, ""); FLAG_MANAGER_ACONFIG_FLAG(reject_dupe_layerstacks, ""); +FLAG_MANAGER_ACONFIG_FLAG(synced_resolution_switch, ""); /// Trunk stable server (R/W) flags /// FLAG_MANAGER_ACONFIG_FLAG(refresh_rate_overlay_on_external_display, "") diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h index 073302eda0..de3f359d7e 100644 --- a/services/surfaceflinger/common/include/common/FlagManager.h +++ b/services/surfaceflinger/common/include/common/FlagManager.h @@ -107,6 +107,7 @@ public: bool restore_blur_step() const; bool skip_invisible_windows_in_input() const; bool stable_edid_ids() const; + bool synced_resolution_switch() const; bool trace_frame_rate_override() const; bool true_hdr_screenshots() const; bool use_known_refresh_rate_for_fps_consistency() const; diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig index 96ab7ab614..fa1da45e41 100644 --- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig @@ -265,6 +265,13 @@ flag { } # stable_edid_ids flag { + name: "synced_resolution_switch" + namespace: "core_graphics" + description: "Synchronize resolution modeset with framebuffer resizing" + bug: "355427258" +} # synced_resolution_switch + +flag { name: "true_hdr_screenshots" namespace: "core_graphics" description: "Enables screenshotting display content in HDR, sans tone mapping" |