SF: Move desired active mode management to DisplayDevice
SF would set the desired active mode on the specific DisplayDevice the
mode was requested and use it to swicth the active display mode.
Change-Id: Ib4f01ec63b2087ab2a81490051d1e029afc71854
Test: SF unit tests
Test: refresh rate switching is working on device with
more than one display
Bug: 187539899
Change-Id: Ie0e5ffe364f81775c2101ffd0cf2c596051947fa
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 60f2408..4445eea 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -22,6 +22,8 @@
#undef LOG_TAG
#define LOG_TAG "DisplayDevice"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include <android-base/stringprintf.h>
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/Display.h>
@@ -66,6 +68,8 @@
mSequenceId(args.sequenceId),
mConnectionType(args.connectionType),
mCompositionDisplay{args.compositionDisplay},
+ mActiveModeFPSTrace("ActiveModeFPS -" + to_string(getId())),
+ mActiveModeFPSHwcTrace("ActiveModeFPS_HWC -" + to_string(getId())),
mPhysicalOrientation(args.physicalOrientation),
mSupportedModes(std::move(args.supportedModes)),
mIsPrimary(args.isPrimary),
@@ -156,6 +160,7 @@
void DisplayDevice::setActiveMode(DisplayModeId id) {
const auto mode = getMode(id);
LOG_FATAL_IF(!mode, "Cannot set active mode which is not supported.");
+ ATRACE_INT(mActiveModeFPSTrace.c_str(), mode->getFps().getIntValue());
mActiveMode = mode;
if (mRefreshRateConfigs) {
mRefreshRateConfigs->setCurrentModeId(mActiveMode->getId());
@@ -165,17 +170,19 @@
}
}
-status_t DisplayDevice::initiateModeChange(DisplayModeId modeId,
+status_t DisplayDevice::initiateModeChange(const ActiveModeInfo& info,
const hal::VsyncPeriodChangeConstraints& constraints,
- hal::VsyncPeriodChangeTimeline* outTimeline) const {
- const auto mode = getMode(modeId);
- if (!mode) {
+ hal::VsyncPeriodChangeTimeline* outTimeline) {
+ if (!info.mode || info.mode->getPhysicalDisplayId() != getPhysicalId()) {
ALOGE("Trying to initiate a mode change to invalid mode %s on display %s",
- std::to_string(modeId.value()).c_str(), to_string(getId()).c_str());
+ info.mode ? std::to_string(info.mode->getId().value()).c_str() : "null",
+ to_string(getId()).c_str());
return BAD_VALUE;
}
- return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), mode->getHwcId(), constraints,
- outTimeline);
+ mUpcomingActiveMode = info;
+ ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), info.mode->getFps().getIntValue());
+ return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), info.mode->getHwcId(),
+ constraints, outTimeline);
}
const DisplayModePtr& DisplayDevice::getActiveMode() const {
@@ -435,6 +442,46 @@
}
}
+bool DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info) {
+ ATRACE_CALL();
+
+ LOG_ALWAYS_FATAL_IF(!info.mode, "desired mode not provided");
+ LOG_ALWAYS_FATAL_IF(getPhysicalId() != info.mode->getPhysicalDisplayId(), "DisplayId mismatch");
+
+ ALOGV("%s(%s)", __func__, to_string(*info.mode).c_str());
+
+ std::scoped_lock lock(mActiveModeLock);
+ if (mDesiredActiveModeChanged) {
+ // If a mode change is pending, just cache the latest request in mDesiredActiveMode
+ const Scheduler::ModeEvent prevConfig = mDesiredActiveMode.event;
+ mDesiredActiveMode = info;
+ mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig;
+ return false;
+ }
+
+ // Check if we are already at the desired mode
+ if (getActiveMode()->getId() == info.mode->getId()) {
+ return false;
+ }
+
+ // Initiate a mode change.
+ mDesiredActiveModeChanged = true;
+ mDesiredActiveMode = info;
+ return true;
+}
+
+std::optional<DisplayDevice::ActiveModeInfo> DisplayDevice::getDesiredActiveMode() const {
+ std::scoped_lock lock(mActiveModeLock);
+ if (mDesiredActiveModeChanged) return mDesiredActiveMode;
+ return std::nullopt;
+}
+
+void DisplayDevice::clearDesiredActiveModeState() {
+ std::scoped_lock lock(mActiveModeLock);
+ mDesiredActiveMode.event = Scheduler::ModeEvent::None;
+ mDesiredActiveModeChanged = false;
+}
+
std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index e7067eb..afd12b5 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -39,6 +39,8 @@
#include <utils/RefBase.h>
#include <utils/Timers.h>
+#include "MainThreadGuard.h"
+
#include "DisplayHardware/DisplayIdentification.h"
#include "DisplayHardware/DisplayMode.h"
#include "DisplayHardware/Hal.h"
@@ -46,6 +48,8 @@
#include "Scheduler/RefreshRateConfigs.h"
+#include "TracedOrdinal.h"
+
namespace android {
class Fence;
@@ -181,10 +185,28 @@
* Display mode management.
*/
const DisplayModePtr& getActiveMode() const;
- void setActiveMode(DisplayModeId);
- status_t initiateModeChange(DisplayModeId modeId,
+
+ struct ActiveModeInfo {
+ DisplayModePtr mode;
+ scheduler::RefreshRateConfigEvent event = scheduler::RefreshRateConfigEvent::None;
+
+ bool operator!=(const ActiveModeInfo& other) const {
+ return mode != other.mode || event != other.event;
+ }
+ };
+
+ bool setDesiredActiveMode(const ActiveModeInfo&) EXCLUDES(mActiveModeLock);
+ std::optional<ActiveModeInfo> getDesiredActiveMode() const EXCLUDES(mActiveModeLock);
+ void clearDesiredActiveModeState() EXCLUDES(mActiveModeLock);
+ ActiveModeInfo getUpcomingActiveMode() const REQUIRES(SF_MAIN_THREAD) {
+ return mUpcomingActiveMode;
+ }
+
+ void setActiveMode(DisplayModeId) REQUIRES(SF_MAIN_THREAD);
+ status_t initiateModeChange(const ActiveModeInfo&,
const hal::VsyncPeriodChangeConstraints& constraints,
- hal::VsyncPeriodChangeTimeline* outTimeline) const;
+ hal::VsyncPeriodChangeTimeline* outTimeline)
+ REQUIRES(SF_MAIN_THREAD);
// Return the immutable list of supported display modes. The HWC may report different modes
// after a hotplug reconnect event, in which case the DisplayDevice object will be recreated.
@@ -236,6 +258,8 @@
const std::shared_ptr<compositionengine::Display> mCompositionDisplay;
std::string mDisplayName;
+ std::string mActiveModeFPSTrace;
+ std::string mActiveModeFPSHwcTrace;
const ui::Rotation mPhysicalOrientation;
ui::Rotation mOrientation = ui::ROTATION_0;
@@ -260,6 +284,12 @@
std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay;
+
+ mutable std::mutex mActiveModeLock;
+ ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock);
+ TracedOrdinal<bool> mDesiredActiveModeChanged
+ GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false};
+ ActiveModeInfo mUpcomingActiveMode GUARDED_BY(SF_MAIN_THREAD);
};
struct DisplayDeviceState {
diff --git a/services/surfaceflinger/MainThreadGuard.h b/services/surfaceflinger/MainThreadGuard.h
new file mode 100644
index 0000000..c1aa118
--- /dev/null
+++ b/services/surfaceflinger/MainThreadGuard.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utils/Mutex.h>
+
+namespace android {
+namespace {
+
+// Helps to ensure that some functions runs on SF's main thread by using the
+// clang thread safety annotations.
+class CAPABILITY("mutex") MainThreadGuard {
+} SF_MAIN_THREAD;
+
+struct SCOPED_CAPABILITY MainThreadScopedGuard {
+public:
+ explicit MainThreadScopedGuard(MainThreadGuard& mutex) ACQUIRE(mutex) {}
+ ~MainThreadScopedGuard() RELEASE() {}
+};
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 2321e2d..2bdcaf6 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -118,12 +118,12 @@
return event;
}
-DisplayEventReceiver::Event makeModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId,
- nsecs_t vsyncPeriod) {
+DisplayEventReceiver::Event makeModeChanged(DisplayModePtr mode) {
DisplayEventReceiver::Event event;
- event.header = {DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE, displayId, systemTime()};
- event.modeChange.modeId = modeId.value();
- event.modeChange.vsyncPeriod = vsyncPeriod;
+ event.header = {DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE, mode->getPhysicalDisplayId(),
+ systemTime()};
+ event.modeChange.modeId = mode->getId().value();
+ event.modeChange.vsyncPeriod = mode->getVsyncPeriod();
return event;
}
@@ -375,11 +375,10 @@
mCondition.notify_all();
}
-void EventThread::onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId,
- nsecs_t vsyncPeriod) {
+void EventThread::onModeChanged(DisplayModePtr mode) {
std::lock_guard<std::mutex> lock(mMutex);
- mPendingEvents.push_back(makeModeChanged(displayId, modeId, vsyncPeriod));
+ mPendingEvents.push_back(makeModeChanged(mode));
mCondition.notify_all();
}
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 1e6793f..9265a25 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -124,8 +124,7 @@
virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0;
// called when SF changes the active mode and apps needs to be notified about the change
- virtual void onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId,
- nsecs_t vsyncPeriod) = 0;
+ virtual void onModeChanged(DisplayModePtr) = 0;
// called when SF updates the Frame Rate Override list
virtual void onFrameRateOverridesChanged(PhysicalDisplayId displayId,
@@ -174,8 +173,7 @@
void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override;
- void onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId,
- nsecs_t vsyncPeriod) override;
+ void onModeChanged(DisplayModePtr) override;
void onFrameRateOverridesChanged(PhysicalDisplayId displayId,
std::vector<FrameRateOverride> overrides) override;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 5fc19da..4a9a1fd 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -71,6 +71,7 @@
int32_t getModeGroup() const { return mode->getGroup(); }
std::string getName() const { return to_string(getFps()); }
Fps getFps() const { return mode->getFps(); }
+ DisplayModePtr getMode() const { return mode; }
// Checks whether the fps of this RefreshRate struct is within a given min and max refresh
// rate passed in. Margin of error is applied to the boundaries for approximation.
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 861f3ac..f808981 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -371,23 +371,22 @@
thread->onFrameRateOverridesChanged(displayId, std::move(overrides));
}
-void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
- DisplayModeId modeId, nsecs_t vsyncPeriod) {
+void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) {
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
// Cache the last reported modes for primary display.
- mFeatures.cachedModeChangedParams = {handle, displayId, modeId, vsyncPeriod};
+ mFeatures.cachedModeChangedParams = {handle, mode};
// Invalidate content based refresh rate selection so it could be calculated
// again for the new refresh rate.
mFeatures.contentRequirements.clear();
}
- onNonPrimaryDisplayModeChanged(handle, displayId, modeId, vsyncPeriod);
+ onNonPrimaryDisplayModeChanged(handle, mode);
}
void Scheduler::dispatchCachedReportedMode() {
// Check optional fields first.
- if (!mFeatures.modeId.has_value()) {
+ if (!mFeatures.mode) {
ALOGW("No mode ID found, not dispatching cached mode.");
return;
}
@@ -396,35 +395,24 @@
return;
}
- const auto modeId = *mFeatures.modeId;
- const auto vsyncPeriod = [&] {
- std::scoped_lock lock(mRefreshRateConfigsLock);
- return mRefreshRateConfigs->getRefreshRateFromModeId(modeId).getVsyncPeriod();
- }();
-
// If there is no change from cached mode, there is no need to dispatch an event
- if (modeId == mFeatures.cachedModeChangedParams->modeId &&
- vsyncPeriod == mFeatures.cachedModeChangedParams->vsyncPeriod) {
+ if (mFeatures.mode == mFeatures.cachedModeChangedParams->mode) {
return;
}
- mFeatures.cachedModeChangedParams->modeId = modeId;
- mFeatures.cachedModeChangedParams->vsyncPeriod = vsyncPeriod;
+ mFeatures.cachedModeChangedParams->mode = mFeatures.mode;
onNonPrimaryDisplayModeChanged(mFeatures.cachedModeChangedParams->handle,
- mFeatures.cachedModeChangedParams->displayId,
- mFeatures.cachedModeChangedParams->modeId,
- mFeatures.cachedModeChangedParams->vsyncPeriod);
+ mFeatures.cachedModeChangedParams->mode);
}
-void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
- DisplayModeId modeId, nsecs_t vsyncPeriod) {
+void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) {
android::EventThread* thread;
{
std::lock_guard<std::mutex> lock(mConnectionsLock);
RETURN_IF_INVALID_HANDLE(handle);
thread = mConnections[handle].thread.get();
}
- thread->onModeChanged(displayId, modeId, vsyncPeriod);
+ thread->onModeChanged(mode);
}
size_t Scheduler::getEventThreadConnectionCount(ConnectionHandle handle) {
@@ -642,19 +630,17 @@
scheduler::LayerHistory::Summary summary =
mLayerHistory->summarize(*refreshRateConfigs, systemTime());
scheduler::RefreshRateConfigs::GlobalSignals consideredSignals;
- DisplayModeId newModeId;
+ DisplayModePtr newMode;
bool frameRateChanged;
bool frameRateOverridesChanged;
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
mFeatures.contentRequirements = summary;
- newModeId = calculateRefreshRateModeId(&consideredSignals);
- auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newModeId);
- frameRateOverridesChanged =
- updateFrameRateOverrides(consideredSignals, newRefreshRate.getFps());
+ newMode = calculateRefreshRateModeId(&consideredSignals);
+ frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
- if (mFeatures.modeId == newModeId) {
+ if (mFeatures.mode == newMode) {
// We don't need to change the display mode, but we might need to send an event
// about a mode change, since it was suppressed due to a previous idleConsidered
if (!consideredSignals.idle) {
@@ -662,12 +648,12 @@
}
frameRateChanged = false;
} else {
- mFeatures.modeId = newModeId;
+ mFeatures.mode = newMode;
frameRateChanged = true;
}
}
if (frameRateChanged) {
- auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newModeId);
+ auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId());
mSchedulerCallback.changeRefreshRate(newRefreshRate,
consideredSignals.idle ? ModeEvent::None
: ModeEvent::Changed);
@@ -820,7 +806,7 @@
template <class T>
bool Scheduler::handleTimerStateChanged(T* currentState, T newState) {
- DisplayModeId newModeId;
+ DisplayModePtr newMode;
bool refreshRateChanged = false;
bool frameRateOverridesChanged;
scheduler::RefreshRateConfigs::GlobalSignals consideredSignals;
@@ -831,23 +817,22 @@
return false;
}
*currentState = newState;
- newModeId = calculateRefreshRateModeId(&consideredSignals);
- const RefreshRate& newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newModeId);
- frameRateOverridesChanged =
- updateFrameRateOverrides(consideredSignals, newRefreshRate.getFps());
- if (mFeatures.modeId == newModeId) {
+ newMode = calculateRefreshRateModeId(&consideredSignals);
+ frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps());
+ if (mFeatures.mode == newMode) {
// We don't need to change the display mode, but we might need to send an event
// about a mode change, since it was suppressed due to a previous idleConsidered
if (!consideredSignals.idle) {
dispatchCachedReportedMode();
}
} else {
- mFeatures.modeId = newModeId;
+ mFeatures.mode = newMode;
refreshRateChanged = true;
}
}
if (refreshRateChanged) {
- const RefreshRate& newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newModeId);
+ const RefreshRate& newRefreshRate =
+ refreshRateConfigs->getRefreshRateFromModeId(newMode->getId());
mSchedulerCallback.changeRefreshRate(newRefreshRate,
consideredSignals.idle ? ModeEvent::None
@@ -859,7 +844,7 @@
return consideredSignals.touch;
}
-DisplayModeId Scheduler::calculateRefreshRateModeId(
+DisplayModePtr Scheduler::calculateRefreshRateModeId(
scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals) {
ATRACE_CALL();
if (consideredSignals) *consideredSignals = {};
@@ -870,7 +855,7 @@
if (mDisplayPowerTimer &&
(!mFeatures.isDisplayPowerStateNormal ||
mFeatures.displayPowerTimer == TimerState::Reset)) {
- return refreshRateConfigs->getMaxRefreshRateByPolicy().getModeId();
+ return refreshRateConfigs->getMaxRefreshRateByPolicy().getMode();
}
const bool touchActive = mTouchTimer && mFeatures.touch == TouchState::Active;
@@ -879,16 +864,16 @@
return refreshRateConfigs
->getBestRefreshRate(mFeatures.contentRequirements,
{.touch = touchActive, .idle = idle}, consideredSignals)
- .getModeId();
+ .getMode();
}
-std::optional<DisplayModeId> Scheduler::getPreferredModeId() {
+DisplayModePtr Scheduler::getPreferredDisplayMode() {
std::lock_guard<std::mutex> lock(mFeatureStateLock);
// Make sure that the default mode ID is first updated, before returned.
- if (mFeatures.modeId.has_value()) {
- mFeatures.modeId = calculateRefreshRateModeId();
+ if (mFeatures.mode) {
+ mFeatures.mode = calculateRefreshRateModeId();
}
- return mFeatures.modeId;
+ return mFeatures.mode;
}
void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index dc17f90..4b6905b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -87,10 +87,8 @@
sp<EventThreadConnection> getEventConnection(ConnectionHandle);
void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected);
- void onPrimaryDisplayModeChanged(ConnectionHandle, PhysicalDisplayId, DisplayModeId,
- nsecs_t vsyncPeriod) EXCLUDES(mFeatureStateLock);
- void onNonPrimaryDisplayModeChanged(ConnectionHandle, PhysicalDisplayId, DisplayModeId,
- nsecs_t vsyncPeriod);
+ void onPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr) EXCLUDES(mFeatureStateLock);
+ void onNonPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr);
void onScreenAcquired(ConnectionHandle);
void onScreenReleased(ConnectionHandle);
@@ -157,7 +155,7 @@
void dumpVsync(std::string&) const;
// Get the appropriate refresh for current conditions.
- std::optional<DisplayModeId> getPreferredModeId();
+ DisplayModePtr getPreferredDisplayMode();
// Notifies the scheduler about a refresh rate timeline change.
void onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline);
@@ -245,7 +243,7 @@
// This function checks whether individual features that are affecting the refresh rate
// selection were initialized, prioritizes them, and calculates the DisplayModeId
// for the suggested refresh rate.
- DisplayModeId calculateRefreshRateModeId(
+ DisplayModePtr calculateRefreshRateModeId(
scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr)
REQUIRES(mFeatureStateLock);
@@ -308,7 +306,7 @@
TouchState touch = TouchState::Inactive;
TimerState displayPowerTimer = TimerState::Expired;
- std::optional<DisplayModeId> modeId;
+ DisplayModePtr mode;
LayerHistory::Summary contentRequirements;
bool isDisplayPowerStateNormal = true;
@@ -316,9 +314,7 @@
// Used to cache the last parameters of onPrimaryDisplayModeChanged
struct ModeChangedParams {
ConnectionHandle handle;
- PhysicalDisplayId displayId;
- DisplayModeId modeId;
- nsecs_t vsyncPeriod;
+ DisplayModePtr mode;
};
std::optional<ModeChangedParams> cachedModeChangedParams;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0892d65..f7ba9e2 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -145,6 +145,13 @@
return (expr); \
}()
+#define MAIN_THREAD_GUARD(expr) \
+ [&] { \
+ LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \
+ MainThreadScopedGuard lock(SF_MAIN_THREAD); \
+ return (expr); \
+ }()
+
#undef NO_THREAD_SAFETY_ANALYSIS
#define NO_THREAD_SAFETY_ANALYSIS \
_Pragma("GCC error \"Prefer MAIN_THREAD macros or {Conditional,Timed,Unnecessary}Lock.\"")
@@ -1073,41 +1080,28 @@
void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) {
ATRACE_CALL();
- const auto display = getDefaultDisplayDeviceLocked();
+
+ if (!info.mode) {
+ ALOGW("requested display mode is null");
+ return;
+ }
+ auto display = getDisplayDeviceLocked(info.mode->getPhysicalDisplayId());
if (!display) {
- ALOGW("%s: default display is null", __func__);
+ ALOGW("%s: display is no longer valid", __func__);
return;
}
- auto refreshRate = display->refreshRateConfigs().getRefreshRateFromModeId(info.modeId);
- ALOGV("%s(%s)", __func__, refreshRate.getName().c_str());
-
- std::lock_guard<std::mutex> lock(mActiveModeLock);
- if (mDesiredActiveModeChanged) {
- // If a mode change is pending, just cache the latest request in mDesiredActiveMode
- const Scheduler::ModeEvent prevConfig = mDesiredActiveMode.event;
- mDesiredActiveMode = info;
- mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig;
- } else {
- // Check if we are already at the desired mode
- if (display->getActiveMode()->getId() == refreshRate.getModeId()) {
- return;
- }
-
- // Initiate a mode change.
- mDesiredActiveModeChanged = true;
- mDesiredActiveMode = info;
-
+ if (display->setDesiredActiveMode(info)) {
// This will trigger HWC refresh without resetting the idle timer.
repaintEverythingForHWC();
// Start receiving vsync samples now, so that we can detect a period
// switch.
- mScheduler->resyncToHardwareVsync(true, refreshRate.getVsyncPeriod());
+ mScheduler->resyncToHardwareVsync(true, info.mode->getVsyncPeriod());
// As we called to set period, we will call to onRefreshRateChangeCompleted once
// VsyncController model is locked.
modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated);
- updatePhaseConfiguration(refreshRate.getFps());
+ updatePhaseConfiguration(info.mode->getFps());
mScheduler->setModeChangePending(true);
}
}
@@ -1161,58 +1155,43 @@
return;
}
- const auto upcomingMode = display->getMode(mUpcomingActiveMode.modeId);
- if (!upcomingMode) {
- ALOGW("Upcoming active mode is no longer supported. Mode ID = %d",
- mUpcomingActiveMode.modeId.value());
- // TODO(b/159590486) Handle the error better. Some parts of SurfaceFlinger may
- // have been already updated with the upcoming active mode.
- return;
- }
-
- if (display->getActiveMode()->getSize() != upcomingMode->getSize()) {
+ const auto upcomingModeInfo = MAIN_THREAD_GUARD(display->getUpcomingActiveMode());
+ if (display->getActiveMode()->getSize() != upcomingModeInfo.mode->getSize()) {
auto& state = mCurrentState.displays.editValueFor(display->getDisplayToken());
// We need to generate new sequenceId in order to recreate the display (and this
// way the framebuffer).
state.sequenceId = DisplayDeviceState{}.sequenceId;
- state.physical->activeMode = upcomingMode;
+ state.physical->activeMode = upcomingModeInfo.mode;
processDisplayChangesLocked();
// processDisplayChangesLocked will update all necessary components so we're done here.
return;
}
- std::lock_guard<std::mutex> lock(mActiveModeLock);
- display->setActiveMode(mUpcomingActiveMode.modeId);
+ // We just created this display so we can call even if we are not on
+ // the main thread
+ MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD);
+ display->setActiveMode(upcomingModeInfo.mode->getId());
- const Fps refreshRate = upcomingMode->getFps();
-
+ const Fps refreshRate = upcomingModeInfo.mode->getFps();
mRefreshRateStats->setRefreshRate(refreshRate);
-
updatePhaseConfiguration(refreshRate);
- ATRACE_INT("ActiveConfigFPS", refreshRate.getValue());
- if (mUpcomingActiveMode.event != Scheduler::ModeEvent::None) {
- const nsecs_t vsyncPeriod = refreshRate.getPeriodNsecs();
- const auto physicalId = display->getPhysicalId();
- mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, physicalId,
- mUpcomingActiveMode.modeId, vsyncPeriod);
+ if (upcomingModeInfo.event != Scheduler::ModeEvent::None) {
+ mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, upcomingModeInfo.mode);
}
}
-void SurfaceFlinger::clearDesiredActiveModeState() {
- std::lock_guard<std::mutex> lock(mActiveModeLock);
- mDesiredActiveMode.event = Scheduler::ModeEvent::None;
- mDesiredActiveModeChanged = false;
- mScheduler->setModeChangePending(false);
+void SurfaceFlinger::clearDesiredActiveModeState(const sp<DisplayDevice>& display) {
+ display->clearDesiredActiveModeState();
+ if (isDisplayActiveLocked(display)) {
+ mScheduler->setModeChangePending(false);
+ }
}
-void SurfaceFlinger::desiredActiveModeChangeDone() {
- const auto modeId = getDesiredActiveMode()->modeId;
-
- clearDesiredActiveModeState();
-
- const auto refreshRate = getDefaultDisplayDeviceLocked()->getMode(modeId)->getFps();
+void SurfaceFlinger::desiredActiveModeChangeDone(const sp<DisplayDevice>& display) {
+ const auto refreshRate = display->getDesiredActiveMode()->mode->getFps();
+ clearDesiredActiveModeState(display);
mScheduler->resyncToHardwareVsync(true, refreshRate.getPeriodNsecs());
updatePhaseConfiguration(refreshRate);
}
@@ -1220,63 +1199,75 @@
void SurfaceFlinger::performSetActiveMode() {
ATRACE_CALL();
ALOGV("%s", __FUNCTION__);
- // Store the local variable to release the lock.
- const auto desiredActiveMode = getDesiredActiveMode();
- if (!desiredActiveMode) {
- // No desired active mode pending to be applied
- return;
+
+ for (const auto& iter : mDisplays) {
+ const auto& display = iter.second;
+ if (!display || !display->isInternal()) {
+ continue;
+ }
+
+ // Store the local variable to release the lock.
+ const auto desiredActiveMode = display->getDesiredActiveMode();
+ if (!desiredActiveMode) {
+ // No desired active mode pending to be applied
+ continue;
+ }
+
+ if (!isDisplayActiveLocked(display)) {
+ // display is no longer the active display, so abort the mode change
+ clearDesiredActiveModeState(display);
+ continue;
+ }
+
+ const auto desiredMode = display->getMode(desiredActiveMode->mode->getId());
+ if (!desiredMode) {
+ ALOGW("Desired display mode is no longer supported. Mode ID = %d",
+ desiredActiveMode->mode->getId().value());
+ clearDesiredActiveModeState(display);
+ continue;
+ }
+
+ const auto refreshRate = desiredMode->getFps();
+ ALOGV("%s changing active mode to %d(%s) for display %s", __func__,
+ desiredMode->getId().value(), to_string(refreshRate).c_str(),
+ to_string(display->getId()).c_str());
+
+ if (display->getActiveMode()->getId() == desiredActiveMode->mode->getId()) {
+ // display is not valid or we are already in the requested mode
+ // on both cases there is nothing left to do
+ desiredActiveModeChangeDone(display);
+ continue;
+ }
+
+ // Desired active mode was set, it is different than the mode currently in use, however
+ // allowed modes might have changed by the time we process the refresh.
+ // Make sure the desired mode is still allowed
+ const auto displayModeAllowed =
+ display->refreshRateConfigs().isModeAllowed(desiredActiveMode->mode->getId());
+ if (!displayModeAllowed) {
+ desiredActiveModeChangeDone(display);
+ continue;
+ }
+
+ // TODO(b/142753666) use constrains
+ hal::VsyncPeriodChangeConstraints constraints;
+ constraints.desiredTimeNanos = systemTime();
+ constraints.seamlessRequired = false;
+ hal::VsyncPeriodChangeTimeline outTimeline;
+
+ const auto status = MAIN_THREAD_GUARD(
+ display->initiateModeChange(*desiredActiveMode, constraints, &outTimeline));
+ if (status != NO_ERROR) {
+ // initiateModeChange may fail if a hotplug event is just about
+ // to be sent. We just log the error in this case.
+ ALOGW("initiateModeChange failed: %d", status);
+ continue;
+ }
+ mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline);
+
+ // Scheduler will submit an empty frame to HWC if needed.
+ mSetActiveModePending = true;
}
-
- const auto display = getDefaultDisplayDeviceLocked();
- const auto desiredMode = display->getMode(desiredActiveMode->modeId);
- if (!desiredMode) {
- ALOGW("Desired display mode is no longer supported. Mode ID = %d",
- desiredActiveMode->modeId.value());
- clearDesiredActiveModeState();
- return;
- }
- const auto refreshRate = desiredMode->getFps();
- ALOGV("%s changing active mode to %d(%s)", __FUNCTION__, desiredMode->getId().value(),
- to_string(refreshRate).c_str());
-
- if (!display || display->getActiveMode()->getId() == desiredActiveMode->modeId) {
- // display is not valid or we are already in the requested mode
- // on both cases there is nothing left to do
- desiredActiveModeChangeDone();
- return;
- }
-
- // Desired active mode was set, it is different than the mode currently in use, however
- // allowed modes might have changed by the time we process the refresh.
- // Make sure the desired mode is still allowed
- if (!isDisplayModeAllowed(desiredActiveMode->modeId)) {
- desiredActiveModeChangeDone();
- return;
- }
-
- mUpcomingActiveMode = *desiredActiveMode;
-
- ATRACE_INT("ActiveModeFPS_HWC", refreshRate.getValue());
-
- // TODO(b/142753666) use constrains
- hal::VsyncPeriodChangeConstraints constraints;
- constraints.desiredTimeNanos = systemTime();
- constraints.seamlessRequired = false;
-
- hal::VsyncPeriodChangeTimeline outTimeline;
- const auto status =
- display->initiateModeChange(mUpcomingActiveMode.modeId, constraints, &outTimeline);
- if (status != NO_ERROR) {
- // initiateModeChange may fail if a hotplug event is just about
- // to be sent. We just log the error in this case.
- ALOGW("initiateModeChange failed: %d", status);
- return;
- }
-
- mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline);
-
- // Scheduler will submit an empty frame to HWC if needed.
- mSetActiveModePending = true;
}
void SurfaceFlinger::disableExpensiveRendering() {
@@ -1743,15 +1734,6 @@
*compositorTiming = getBE().mCompositorTiming;
}
-bool SurfaceFlinger::isDisplayModeAllowed(DisplayModeId modeId) const {
- const auto display = getDefaultDisplayDeviceLocked();
- if (display) {
- return display->refreshRateConfigs().isModeAllowed(modeId);
- }
- ALOGW("%s: default display is null", __func__);
- return false;
-}
-
void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate,
Scheduler::ModeEvent event) {
const auto display = getDefaultDisplayDeviceLocked();
@@ -1761,13 +1743,13 @@
ATRACE_CALL();
// Don't do any updating if the current fps is the same as the new one.
- if (!isDisplayModeAllowed(refreshRate.getModeId())) {
+ if (!display->refreshRateConfigs().isModeAllowed(refreshRate.getModeId())) {
ALOGV("Skipping mode %d as it is not part of allowed modes",
refreshRate.getModeId().value());
return;
}
- setDesiredActiveMode({refreshRate.getModeId(), event});
+ setDesiredActiveMode({refreshRate.getMode(), event});
}
void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId,
@@ -2711,7 +2693,7 @@
RenderIntent::COLORIMETRIC,
Dataspace::UNKNOWN});
if (!state.isVirtual()) {
- display->setActiveMode(state.physical->activeMode->getId());
+ MAIN_THREAD_GUARD(display->setActiveMode(state.physical->activeMode->getId()));
display->setDeviceProductInfo(state.physical->deviceProductInfo);
}
@@ -3135,7 +3117,6 @@
ALOGW("Can't re-init scheduler");
return;
}
- const auto displayId = display->getId();
const auto currRefreshRate = display->getActiveMode()->getFps();
mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, currRefreshRate,
hal::PowerMode::OFF);
@@ -3173,9 +3154,7 @@
// This is a bit hacky, but this avoids a back-pointer into the main SF
// classes from EventThread, and there should be no run-time binder cost
// anyway since there are no connected apps at this point.
- mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle,
- *PhysicalDisplayId::tryCast(displayId),
- display->getActiveMode()->getId(), vsyncPeriod);
+ mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, display->getActiveMode());
static auto ignorePresentFences =
base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false);
mScheduler->setIgnorePresentFences(
@@ -5788,16 +5767,19 @@
// Update the overlay on the main thread to avoid race conditions with
// mRefreshRateConfigs->getCurrentRefreshRate()
static_cast<void>(schedule([=] {
- const auto desiredActiveMode = getDesiredActiveMode();
- const std::optional<DisplayModeId> desiredModeId =
- desiredActiveMode ? std::make_optional(desiredActiveMode->modeId) : std::nullopt;
-
- const bool timerExpired = mKernelIdleTimerEnabled && expired;
const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
if (!display) {
ALOGW("%s: default display is null", __func__);
return;
}
+
+ const auto desiredActiveMode = display->getDesiredActiveMode();
+ const std::optional<DisplayModeId> desiredModeId = desiredActiveMode
+ ? std::make_optional(desiredActiveMode->mode->getId())
+ : std::nullopt;
+
+ const bool timerExpired = mKernelIdleTimerEnabled && expired;
+
if (display->onKernelTimerChanged(desiredModeId, timerExpired)) {
mEventQueue->invalidate();
}
@@ -6432,12 +6414,6 @@
const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) {
Mutex::Autolock lock(mStateLock);
- const bool isDefaultDisplay = display == getDefaultDisplayDeviceLocked();
-
- LOG_ALWAYS_FATAL_IF(!isDefaultDisplay && overridePolicy,
- "Can only set override policy on the default display");
- LOG_ALWAYS_FATAL_IF(!policy && !overridePolicy, "Can only clear the override policy");
-
if (mDebugDisplayModeSetByBackdoor) {
// ignore this request as mode is overridden by backdoor
return NO_ERROR;
@@ -6453,32 +6429,6 @@
return NO_ERROR;
}
- if (!isDefaultDisplay) {
- // TODO(b/144711714): For non-default displays we should be able to set an active mode
- // as well. For now, just call directly to initiateModeChange but ideally
- // it should go thru setDesiredActiveMode, similar to primary display.
- ALOGV("%s for non-default display", __func__);
- const auto displayId = display->getPhysicalId();
-
- hal::VsyncPeriodChangeConstraints constraints;
- constraints.desiredTimeNanos = systemTime();
- constraints.seamlessRequired = false;
-
- hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0};
- if (display->initiateModeChange(policy->defaultMode, constraints, &timeline) != NO_ERROR) {
- return BAD_VALUE;
- }
- if (timeline.refreshRequired) {
- repaintEverythingForHWC();
- }
-
- display->setActiveMode(policy->defaultMode);
- const nsecs_t vsyncPeriod = display->getMode(policy->defaultMode)->getVsyncPeriod();
- mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, displayId,
- policy->defaultMode, vsyncPeriod);
- return NO_ERROR;
- }
-
scheduler::RefreshRateConfigs::Policy currentPolicy =
display->refreshRateConfigs().getCurrentPolicy();
@@ -6487,25 +6437,32 @@
// TODO(b/140204874): Leave the event in until we do proper testing with all apps that might
// be depending in this callback.
const auto activeMode = display->getActiveMode();
- const nsecs_t vsyncPeriod = activeMode->getVsyncPeriod();
- const auto physicalId = display->getPhysicalId();
- mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, physicalId, activeMode->getId(),
- vsyncPeriod);
- toggleKernelIdleTimer();
+ if (isDisplayActiveLocked(display)) {
+ mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode);
+ toggleKernelIdleTimer();
+ } else {
+ mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode);
+ }
- auto modeId = mScheduler->getPreferredModeId() ? *mScheduler->getPreferredModeId()
- : currentPolicy.defaultMode;
- auto preferredRefreshRate = display->refreshRateConfigs().getRefreshRateFromModeId(modeId);
+ const DisplayModePtr preferredDisplayMode = [&] {
+ const auto schedulerMode = mScheduler->getPreferredDisplayMode();
+ if (schedulerMode && schedulerMode->getPhysicalDisplayId() == display->getPhysicalId()) {
+ return schedulerMode;
+ }
+
+ return display->getMode(currentPolicy.defaultMode);
+ }();
+
ALOGV("trying to switch to Scheduler preferred mode %d (%s)",
- preferredRefreshRate.getModeId().value(), preferredRefreshRate.getName().c_str());
+ preferredDisplayMode->getId().value(), to_string(preferredDisplayMode->getFps()).c_str());
- if (isDisplayModeAllowed(preferredRefreshRate.getModeId())) {
+ if (display->refreshRateConfigs().isModeAllowed(preferredDisplayMode->getId())) {
ALOGV("switching to Scheduler preferred display mode %d",
- preferredRefreshRate.getModeId().value());
- setDesiredActiveMode({preferredRefreshRate.getModeId(), Scheduler::ModeEvent::Changed});
+ preferredDisplayMode->getId().value());
+ setDesiredActiveMode({preferredDisplayMode, Scheduler::ModeEvent::Changed});
} else {
LOG_ALWAYS_FATAL("Desired display mode not allowed: %d",
- preferredRefreshRate.getModeId().value());
+ preferredDisplayMode->getId().value());
}
return NO_ERROR;
@@ -6967,6 +6924,7 @@
return;
}
updateInternalDisplayVsyncLocked(activeDisplay);
+ mScheduler->setModeChangePending(false);
mScheduler->setRefreshRateConfigs(activeDisplay->holdRefreshRateConfigs());
onActiveDisplaySizeChanged(activeDisplay);
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b35ec3d..6755bfa 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -453,14 +453,7 @@
mCounterByLayerHandle GUARDED_BY(mLock);
};
- struct ActiveModeInfo {
- DisplayModeId modeId;
- Scheduler::ModeEvent event = Scheduler::ModeEvent::None;
-
- bool operator!=(const ActiveModeInfo& other) const {
- return modeId != other.modeId || event != other.event;
- }
- };
+ using ActiveModeInfo = DisplayDevice::ActiveModeInfo;
enum class BootStage {
BOOTLOADER,
@@ -778,9 +771,9 @@
// Calls to setActiveMode on the main thread if there is a pending mode change
// that needs to be applied.
void performSetActiveMode() REQUIRES(mStateLock);
- void clearDesiredActiveModeState() REQUIRES(mStateLock) EXCLUDES(mActiveModeLock);
+ void clearDesiredActiveModeState(const sp<DisplayDevice>&) REQUIRES(mStateLock);
// Called when active mode is no longer is progress
- void desiredActiveModeChangeDone() REQUIRES(mStateLock);
+ void desiredActiveModeChangeDone(const sp<DisplayDevice>&) REQUIRES(mStateLock);
// Called on the main thread in response to setPowerMode()
void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode)
REQUIRES(mStateLock);
@@ -950,6 +943,18 @@
return it == mDisplays.end() ? nullptr : it->second;
}
+ sp<const DisplayDevice> getDisplayDeviceLocked(PhysicalDisplayId id) const
+ REQUIRES(mStateLock) {
+ return const_cast<SurfaceFlinger*>(this)->getDisplayDeviceLocked(id);
+ }
+
+ sp<DisplayDevice> getDisplayDeviceLocked(PhysicalDisplayId id) REQUIRES(mStateLock) {
+ if (const auto token = getPhysicalDisplayTokenLocked(id)) {
+ return getDisplayDeviceLocked(token);
+ }
+ return nullptr;
+ }
+
sp<const DisplayDevice> getDefaultDisplayDeviceLocked() const REQUIRES(mStateLock) {
return const_cast<SurfaceFlinger*>(this)->getDefaultDisplayDeviceLocked();
}
@@ -1053,8 +1058,6 @@
// the desired refresh rate.
void changeRefreshRateLocked(const RefreshRate&, Scheduler::ModeEvent) REQUIRES(mStateLock);
- bool isDisplayModeAllowed(DisplayModeId) const REQUIRES(mStateLock);
-
struct FenceWithFenceTime {
sp<Fence> fence = Fence::NO_FENCE;
std::shared_ptr<FenceTime> fenceTime = FenceTime::NO_FENCE;
@@ -1188,13 +1191,6 @@
/*
* Misc
*/
-
- std::optional<ActiveModeInfo> getDesiredActiveMode() EXCLUDES(mActiveModeLock) {
- std::lock_guard<std::mutex> lock(mActiveModeLock);
- if (mDesiredActiveModeChanged) return mDesiredActiveMode;
- return std::nullopt;
- }
-
std::vector<ui::ColorMode> getDisplayColorModes(PhysicalDisplayId displayId)
REQUIRES(mStateLock);
@@ -1407,17 +1403,7 @@
nsecs_t mScheduledPresentTime = 0;
hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
- std::mutex mActiveModeLock;
- // This bit is set once we start setting the mode. We read from this bit during the
- // process. If at the end, this bit is different than mDesiredActiveMode, we restart
- // the process.
- ActiveModeInfo mUpcomingActiveMode; // Always read and written on the main thread.
- // This bit can be set at any point in time when the system wants the new mode.
- ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock);
-
// below flags are set by main thread only
- TracedOrdinal<bool> mDesiredActiveModeChanged
- GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false};
bool mSetActiveModePending = false;
bool mLumaSampling = true;
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index bd6fe1d..8bd6e62 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -54,6 +54,7 @@
"DisplayIdGeneratorTest.cpp",
"DisplayTransactionTest.cpp",
"DisplayDevice_GetBestColorModeTest.cpp",
+ "DisplayDevice_InitiateModeChange.cpp",
"DisplayDevice_SetProjectionTest.cpp",
"EventThreadTest.cpp",
"FpsReporterTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
new file mode 100644
index 0000000..d4cfbbb
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+class InitiateModeChangeTest : public DisplayTransactionTest {
+public:
+ using Event = scheduler::RefreshRateConfigEvent;
+
+ void SetUp() override {
+ injectFakeBufferQueueFactory();
+ injectFakeNativeWindowSurfaceFactory();
+
+ PrimaryDisplayVariant::setupHwcHotplugCallExpectations(this);
+ PrimaryDisplayVariant::setupFramebufferConsumerBufferQueueCallExpectations(this);
+ PrimaryDisplayVariant::setupFramebufferProducerBufferQueueCallExpectations(this);
+ PrimaryDisplayVariant::setupNativeWindowSurfaceCreationCallExpectations(this);
+ PrimaryDisplayVariant::setupHwcGetActiveConfigCallExpectations(this);
+
+ mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED);
+
+ mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this)
+ .setSupportedModes({kDisplayMode60, kDisplayMode90, kDisplayMode120})
+ .setActiveMode(kDisplayModeId60)
+ .inject();
+ }
+
+protected:
+ sp<DisplayDevice> mDisplay;
+
+ const DisplayModeId kDisplayModeId60 = DisplayModeId(0);
+ const DisplayModePtr kDisplayMode60 =
+ DisplayMode::Builder(hal::HWConfigId(kDisplayModeId60.value()))
+ .setId(kDisplayModeId60)
+ .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get())
+ .setVsyncPeriod(int32_t(16'666'667))
+ .setGroup(0)
+ .setHeight(1000)
+ .setWidth(1000)
+ .build();
+
+ const DisplayModeId kDisplayModeId90 = DisplayModeId(1);
+ const DisplayModePtr kDisplayMode90 =
+ DisplayMode::Builder(hal::HWConfigId(kDisplayModeId90.value()))
+ .setId(kDisplayModeId90)
+ .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get())
+ .setVsyncPeriod(int32_t(11'111'111))
+ .setGroup(0)
+ .setHeight(1000)
+ .setWidth(1000)
+ .build();
+
+ const DisplayModeId kDisplayModeId120 = DisplayModeId(2);
+ const DisplayModePtr kDisplayMode120 =
+ DisplayMode::Builder(hal::HWConfigId(kDisplayModeId120.value()))
+ .setId(kDisplayModeId120)
+ .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get())
+ .setVsyncPeriod(int32_t(8'333'333))
+ .setGroup(0)
+ .setHeight(1000)
+ .setWidth(1000)
+ .build();
+};
+
+TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setCurrentMode) {
+ EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode60, Event::None}));
+ EXPECT_EQ(std::nullopt, mDisplay->getDesiredActiveMode());
+}
+
+TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setNewMode) {
+ EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+ EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
+
+ // Setting another mode should be cached but return false
+ EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode120, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+ EXPECT_EQ(kDisplayMode120, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
+}
+
+TEST_F(InitiateModeChangeTest, clearDesiredActiveModeState) {
+ EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+
+ mDisplay->clearDesiredActiveModeState();
+ ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode());
+}
+
+TEST_F(InitiateModeChangeTest, initiateModeChange) NO_THREAD_SAFETY_ANALYSIS {
+ EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+ EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
+
+ hal::VsyncPeriodChangeConstraints constraints{
+ .desiredTimeNanos = systemTime(),
+ .seamlessRequired = false,
+ };
+ hal::VsyncPeriodChangeTimeline timeline;
+ EXPECT_EQ(OK,
+ mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints,
+ &timeline));
+ EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
+
+ mDisplay->clearDesiredActiveModeState();
+ ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode());
+}
+
+TEST_F(InitiateModeChangeTest, getUpcomingActiveMode_desiredActiveModeChanged)
+NO_THREAD_SAFETY_ANALYSIS {
+ EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+ EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
+
+ hal::VsyncPeriodChangeConstraints constraints{
+ .desiredTimeNanos = systemTime(),
+ .seamlessRequired = false,
+ };
+ hal::VsyncPeriodChangeTimeline timeline;
+ EXPECT_EQ(OK,
+ mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints,
+ &timeline));
+ EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
+
+ EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode120, Event::None}));
+ ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode());
+ EXPECT_EQ(kDisplayMode120, mDisplay->getDesiredActiveMode()->mode);
+ EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event);
+
+ EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
+
+ EXPECT_EQ(OK,
+ mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints,
+ &timeline));
+ EXPECT_EQ(kDisplayMode120, mDisplay->getUpcomingActiveMode().mode);
+ EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event);
+
+ mDisplay->clearDesiredActiveModeState();
+ ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode());
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 62acc6b..28d0222 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -546,17 +546,34 @@
}
TEST_F(EventThreadTest, postConfigChangedPrimary) {
- mThread->onModeChanged(INTERNAL_DISPLAY_ID, DisplayModeId(7), 16666666);
+ const auto mode = DisplayMode::Builder(hal::HWConfigId(0))
+ .setPhysicalDisplayId(INTERNAL_DISPLAY_ID)
+ .setId(DisplayModeId(7))
+ .setVsyncPeriod(16666666)
+ .build();
+
+ mThread->onModeChanged(mode);
expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7, 16666666);
}
TEST_F(EventThreadTest, postConfigChangedExternal) {
- mThread->onModeChanged(EXTERNAL_DISPLAY_ID, DisplayModeId(5), 16666666);
+ const auto mode = DisplayMode::Builder(hal::HWConfigId(0))
+ .setPhysicalDisplayId(EXTERNAL_DISPLAY_ID)
+ .setId(DisplayModeId(5))
+ .setVsyncPeriod(16666666)
+ .build();
+
+ mThread->onModeChanged(mode);
expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5, 16666666);
}
TEST_F(EventThreadTest, postConfigChangedPrimary64bit) {
- mThread->onModeChanged(DISPLAY_ID_64BIT, DisplayModeId(7), 16666666);
+ const auto mode = DisplayMode::Builder(hal::HWConfigId(0))
+ .setPhysicalDisplayId(DISPLAY_ID_64BIT)
+ .setId(DisplayModeId(7))
+ .setVsyncPeriod(16666666)
+ .build();
+ mThread->onModeChanged(mode);
expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7, 16666666);
}
@@ -565,7 +582,13 @@
sp<MockEventThreadConnection> suppressConnection =
createConnection(suppressConnectionEventRecorder);
- mThread->onModeChanged(INTERNAL_DISPLAY_ID, DisplayModeId(9), 16666666);
+ const auto mode = DisplayMode::Builder(hal::HWConfigId(0))
+ .setPhysicalDisplayId(INTERNAL_DISPLAY_ID)
+ .setId(DisplayModeId(9))
+ .setVsyncPeriod(16666666)
+ .build();
+
+ mThread->onModeChanged(mode);
expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9, 16666666);
auto args = suppressConnectionEventRecorder.waitForCall();
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 6cea4c2..e2b3993 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -199,20 +199,21 @@
// onModeChange is called.
mScheduler->clearOptionalFieldsInFeatures();
EXPECT_NO_FATAL_FAILURE(mScheduler->dispatchCachedReportedMode());
- EXPECT_CALL(*mEventThread, onModeChanged(_, _, _)).Times(0);
+ EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0);
}
TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) {
- DisplayModeId modeId = DisplayModeId(111);
- nsecs_t vsyncPeriod = 111111;
+ const auto mode = DisplayMode::Builder(hal::HWConfigId(0))
+ .setId(DisplayModeId(111))
+ .setPhysicalDisplayId(PHYSICAL_DISPLAY_ID)
+ .setVsyncPeriod(111111)
+ .build();
// If the handle is incorrect, the function should return before
// onModeChange is called.
Scheduler::ConnectionHandle invalidHandle = {.id = 123};
- EXPECT_NO_FATAL_FAILURE(mScheduler->onNonPrimaryDisplayModeChanged(invalidHandle,
- PHYSICAL_DISPLAY_ID, modeId,
- vsyncPeriod));
- EXPECT_CALL(*mEventThread, onModeChanged(_, _, _)).Times(0);
+ EXPECT_NO_FATAL_FAILURE(mScheduler->onNonPrimaryDisplayModeChanged(invalidHandle, mode));
+ EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0);
}
TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) {
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 3b129d5..a99dabe 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -100,9 +100,8 @@
mFeatures.cachedModeChangedParams.reset();
}
- void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
- DisplayModeId modeId, nsecs_t vsyncPeriod) {
- return Scheduler::onNonPrimaryDisplayModeChanged(handle, displayId, modeId, vsyncPeriod);
+ void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) {
+ return Scheduler::onNonPrimaryDisplayModeChanged(handle, mode);
}
~TestableScheduler() {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index c82599b..ad284e3 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -724,7 +724,7 @@
return *this;
}
- sp<DisplayDevice> inject() {
+ sp<DisplayDevice> inject() NO_THREAD_SAFETY_ANALYSIS {
const auto displayId = mCreationArgs.compositionDisplay->getDisplayId();
DisplayDeviceState state;
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 485b4ac..d25973e 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -33,7 +33,7 @@
MOCK_METHOD0(onScreenReleased, void());
MOCK_METHOD0(onScreenAcquired, void());
MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
- MOCK_METHOD3(onModeChanged, void(PhysicalDisplayId, DisplayModeId, nsecs_t));
+ MOCK_METHOD1(onModeChanged, void(DisplayModePtr));
MOCK_METHOD2(onFrameRateOverridesChanged,
void(PhysicalDisplayId, std::vector<FrameRateOverride>));
MOCK_CONST_METHOD1(dump, void(std::string&));