SF: Flow DisplayModeRequest through mode set FSM
The motivation is to:
- Avoid redundant state that can cause data races if stale.
- Consolidate control flow for resolution and refresh rate changes.
- Clarify the desired/pending/active states of the per-display FSM.
The notable changes are:
Consume the desired DisplayModeRequestOpt via either SF::dropModeRequest
or DisplayDevice::initiateModeChange.
Pull the details of SF::finalizeDisplayModeChange into DisplayDevice::
finalizeModeChange, which now returns whether there was NoModeChange,
a ResolutionChange, or a RefreshRateChange. Consume the pending request.
Now that DisplayDevice does not retain the desired DisplayModeRequest,
applyActiveMode as soon as finalizeDisplayModeChange ends, rather than
at a later point in the commit, when initiateDisplayModeChanges checks
whether the active and desired modes are the same.
Now that applyActiveMode happens in finalizeDisplayModeChange, remove
the special case when there is a displayToUpdateImmediately.
Bug: 305813445
Bug: 255635711
Bug: 241285876
Test: ALOGV of mode setting for inner/outer displays
Test: InitiateModeChangeTest, DisplayModeSwitchingTest
Change-Id: I688b0c922747a80e881965a1dc243d11ba2c7438
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index ac390cb..3090477 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -19,6 +19,7 @@
#include <memory>
#include <string>
#include <unordered_map>
+#include <variant>
#include <android-base/thread_annotations.h>
#include <android/native_window.h>
@@ -194,12 +195,11 @@
using DisplayModeRequestOpt = ftl::Optional<display::DisplayModeRequest>;
DisplayModeRequestOpt getDesiredMode() const EXCLUDES(mDesiredModeLock);
- void clearDesiredMode() EXCLUDES(mDesiredModeLock);
+ DisplayModeRequestOpt takeDesiredMode() EXCLUDES(mDesiredModeLock);
- DisplayModeRequestOpt getPendingMode() const REQUIRES(kMainThreadContext) {
- return mPendingModeOpt;
+ bool isModeSetPending() const REQUIRES(kMainThreadContext) {
+ return mPendingModeOpt.has_value();
}
- bool isModeSetPending() const REQUIRES(kMainThreadContext) { return mIsModeSetPending; }
scheduler::FrameRateMode getActiveMode() const REQUIRES(kMainThreadContext) {
return mRefreshRateSelector->getActiveMode();
@@ -211,8 +211,25 @@
hal::VsyncPeriodChangeTimeline& outTimeline)
REQUIRES(kMainThreadContext);
- void finalizeModeChange(DisplayModeId, Fps vsyncRate, Fps renderFps)
- REQUIRES(kMainThreadContext);
+ struct NoModeChange {
+ const char* reason;
+ };
+
+ struct ResolutionChange {
+ display::DisplayModeRequest activeMode;
+ };
+
+ struct RefreshRateChange {
+ display::DisplayModeRequest activeMode;
+ };
+
+ using ModeChange = std::variant<NoModeChange, ResolutionChange, RefreshRateChange>;
+
+ // Clears the pending DisplayModeRequest, and returns the ModeChange that occurred. If it was a
+ // RefreshRateChange, the pending mode becomes the active mode. If it was a ResolutionChange,
+ // the caller is responsible for resizing the framebuffer to match the active resolution by
+ // recreating the DisplayDevice.
+ ModeChange finalizeModeChange() REQUIRES(kMainThreadContext);
scheduler::RefreshRateSelector& refreshRateSelector() const { return *mRefreshRateSelector; }
@@ -249,6 +266,8 @@
void dump(utils::Dumper&) const;
private:
+ friend class TestableSurfaceFlinger;
+
template <size_t N>
inline std::string concatId(const char (&str)[N]) const {
return std::string(ftl::Concat(str, ' ', getId().value).str());
@@ -299,12 +318,15 @@
// This parameter is only used for hdr/sdr ratio overlay
float mHdrSdrRatio = 1.0f;
+ // A DisplayModeRequest flows through three states: desired, pending, and active. Requests
+ // within a frame are merged into a single desired request. Unless cleared, the request is
+ // relayed to HWC on the next frame, and becomes pending. The mode becomes active once HWC
+ // signals the present fence to confirm the mode set.
mutable std::mutex mDesiredModeLock;
DisplayModeRequestOpt mDesiredModeOpt GUARDED_BY(mDesiredModeLock);
TracedOrdinal<bool> mHasDesiredModeTrace GUARDED_BY(mDesiredModeLock);
DisplayModeRequestOpt mPendingModeOpt GUARDED_BY(kMainThreadContext);
- bool mIsModeSetPending GUARDED_BY(kMainThreadContext) = false;
};
struct DisplayDeviceState {