SF: set active config state machine
1) Set the desired active config bit
2) On the next vsync, ask HWC to update config.
3) Send a refresh to HWC
4) When the fence comes back, update SF to the new config/refresh rate
and trigger HWC vsync.
see go/surface-flinger-scheduler for more info
Test: Systrace.
Change-Id: I4ed649668cc6cc23cd3f428b3c92ab1c199c8aa4
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6546973..a748bc5 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -437,7 +437,12 @@
const Rect& sourceCrop, float frameScale, bool childrenOnly) override;
status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
status_t getDisplayConfigs(const sp<IBinder>& displayToken,
- Vector<DisplayInfo>* configs) override;
+ Vector<DisplayInfo>* configs) override {
+ Mutex::Autolock _l(mStateLock);
+ return getDisplayConfigsLocked(displayToken, configs);
+ }
+ status_t getDisplayConfigsLocked(const sp<IBinder>& displayToken, Vector<DisplayInfo>* configs)
+ REQUIRES(mStateLock);
int getActiveConfig(const sp<IBinder>& displayToken) override;
status_t getDisplayColorModes(const sp<IBinder>& displayToken,
Vector<ui::ColorMode>* configs) override;
@@ -503,8 +508,18 @@
// called on the main thread in response to initializeDisplays()
void onInitializeDisplays() REQUIRES(mStateLock);
- // called on the main thread in response to setActiveConfig()
- void setActiveConfigInternal(const sp<IBinder>& displayToken, int mode) REQUIRES(mStateLock);
+ // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
+ void setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode) REQUIRES(mStateLock);
+ // Calls setActiveConfig in HWC.
+ void setActiveConfigInHWC();
+ // Once HWC has returned the present fence, this sets the active config and a new refresh
+ // rate in SF. It also triggers HWC vsync.
+ void setActiveConfigInternal() REQUIRES(mStateLock);
+ // Active config is updated on INVALIDATE call in a state machine-like manner. When the
+ // desired config was set, HWC needs to update the pannel on the next refresh, and when
+ // we receive the fence back, we know that the process was complete. It returns whether
+ // the invalidate process should continue.
+ bool updateSetActiveConfigStateMachine();
// called on the main thread in response to setPowerMode()
void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock);
@@ -1084,6 +1099,34 @@
sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
+ // The following structs are used for configuring active config state at a desired time,
+ // which is once per vsync at invalidate time.
+ enum SetActiveConfigState {
+ NONE, // not in progress
+ NOTIFIED_HWC, // call to HWC has been made
+ REFRESH_RECEIVED // onRefresh was received from HWC
+ };
+ std::atomic<SetActiveConfigState> mSetActiveConfigState = SetActiveConfigState::NONE;
+
+ struct ActiveConfigInfo {
+ int configId;
+ sp<IBinder> displayToken;
+
+ bool operator!=(const ActiveConfigInfo& other) const {
+ if (configId != other.configId) {
+ return true;
+ }
+ return (displayToken != other.displayToken);
+ }
+ };
+ std::mutex mActiveConfigLock;
+ // This bit is set once we start setting the config. We read from this bit during the
+ // process. If at the end, this bit is different than mDesiredActiveConfig, we restart
+ // the process.
+ ActiveConfigInfo mUpcomingActiveConfig; // Always read and written on the main thread.
+ // This bit can be set at any point in time when the system wants the new config.
+ ActiveConfigInfo mDesiredActiveConfig GUARDED_BY(mActiveConfigLock);
+
/* ------------------------------------------------------------------------ */
sp<IInputFlinger> mInputFlinger;