Merge changes Ie0e5ffe3,I9c73b433 into sc-v2-dev
* changes:
SF: Move desired active mode management to DisplayDevice
SF: add PhysicalDisplayId to DisplayMode
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 7db2def..4d435c7 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/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h
index 85cc993..5de622b 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayMode.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h
@@ -22,6 +22,7 @@
#include <android-base/stringprintf.h>
#include <android/configuration.h>
+#include <ui/DisplayId.h>
#include <ui/DisplayMode.h>
#include <ui/Size.h>
#include <utils/Timers.h>
@@ -54,6 +55,11 @@
return *this;
}
+ Builder& setPhysicalDisplayId(PhysicalDisplayId id) {
+ mDisplayMode->mPhysicalDisplayId = id;
+ return *this;
+ }
+
Builder& setWidth(int32_t width) {
mDisplayMode->mWidth = width;
return *this;
@@ -112,6 +118,7 @@
DisplayModeId getId() const { return mId; }
hal::HWConfigId getHwcId() const { return mHwcId; }
+ PhysicalDisplayId getPhysicalDisplayId() const { return mPhysicalDisplayId; }
int32_t getWidth() const { return mWidth; }
int32_t getHeight() const { return mHeight; }
@@ -136,6 +143,7 @@
hal::HWConfigId mHwcId;
DisplayModeId mId;
+ PhysicalDisplayId mPhysicalDisplayId;
int32_t mWidth = -1;
int32_t mHeight = -1;
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 55d8807..e3a324d 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,
@@ -2531,6 +2513,7 @@
for (const auto& hwcMode : hwcModes) {
newModes.push_back(DisplayMode::Builder(hwcMode.hwcId)
.setId(DisplayModeId{nextModeId++})
+ .setPhysicalDisplayId(displayId)
.setWidth(hwcMode.width)
.setHeight(hwcMode.height)
.setVsyncPeriod(hwcMode.vsyncPeriod)
@@ -2710,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);
}
@@ -3134,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);
@@ -3172,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(
@@ -5807,16 +5787,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();
}
@@ -6454,12 +6437,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;
@@ -6475,32 +6452,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();
@@ -6509,25 +6460,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;
@@ -6989,6 +6947,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 6daf02a..9142978 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -456,14 +456,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,
@@ -783,9 +776,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);
@@ -957,6 +950,10 @@
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);
}
@@ -1066,8 +1063,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;
@@ -1201,13 +1196,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);
@@ -1420,17 +1408,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 b5086fa..9e704c3 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -51,6 +51,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 b4a1481..4ff7592 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -543,17 +543,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);
}
@@ -562,7 +579,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/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index d0d5ca4..02ec7fc 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -115,20 +115,20 @@
<< "Frame rate is " << frameRate;
}
- std::shared_ptr<RefreshRateConfigs> mConfigs =
- std::make_shared<RefreshRateConfigs>(DisplayModes{DisplayMode::Builder(0)
- .setId(DisplayModeId(0))
- .setVsyncPeriod(int32_t(
- LO_FPS_PERIOD))
- .setGroup(0)
- .build(),
- DisplayMode::Builder(1)
- .setId(DisplayModeId(1))
- .setVsyncPeriod(int32_t(
- HI_FPS_PERIOD))
- .setGroup(0)
- .build()},
- DisplayModeId(0));
+ std::shared_ptr<RefreshRateConfigs> mConfigs = std::make_shared<
+ RefreshRateConfigs>(DisplayModes{DisplayMode::Builder(0)
+ .setId(DisplayModeId(0))
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
+ .setVsyncPeriod(int32_t(LO_FPS_PERIOD))
+ .setGroup(0)
+ .build(),
+ DisplayMode::Builder(1)
+ .setId(DisplayModeId(1))
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
+ .setVsyncPeriod(int32_t(HI_FPS_PERIOD))
+ .setGroup(0)
+ .build()},
+ DisplayModeId(0));
mock::SchedulerCallback mSchedulerCallback;
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index cc6fa2c..6870fd4 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -181,6 +181,7 @@
int64_t vsyncPeriod, ui::Size resolution) {
return DisplayMode::Builder(hal::HWConfigId(modeId.value()))
.setId(modeId)
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
.setVsyncPeriod(int32_t(vsyncPeriod))
.setGroup(group)
.setHeight(resolution.height)
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index bf07106..12b155b 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -81,6 +81,7 @@
int64_t vsyncPeriod) {
return DisplayMode::Builder(static_cast<hal::HWConfigId>(modeId.value()))
.setId(modeId)
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
.setVsyncPeriod(static_cast<int32_t>(vsyncPeriod))
.setGroup(group)
.build();
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 1f5fec0..5713c2f 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -53,11 +53,13 @@
const DisplayModePtr mode60 = DisplayMode::Builder(0)
.setId(DisplayModeId(0))
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
.setVsyncPeriod(Fps(60.f).getPeriodNsecs())
.setGroup(0)
.build();
const DisplayModePtr mode120 = DisplayMode::Builder(1)
.setId(DisplayModeId(1))
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
.setVsyncPeriod(Fps(120.f).getPeriodNsecs())
.setGroup(0)
.build();
@@ -197,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 0dc5b4f..393387b 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -209,6 +209,7 @@
ISchedulerCallback* callback = nullptr, bool hasMultipleModes = false) {
DisplayModes modes{DisplayMode::Builder(0)
.setId(DisplayModeId(0))
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
.setVsyncPeriod(16'666'667)
.setGroup(0)
.build()};
@@ -216,6 +217,7 @@
if (hasMultipleModes) {
modes.emplace_back(DisplayMode::Builder(1)
.setId(DisplayModeId(1))
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
.setVsyncPeriod(11'111'111)
.setGroup(0)
.build());
@@ -641,6 +643,7 @@
DisplayModePtr activeMode =
DisplayMode::Builder(FakeHwcDisplayInjector::DEFAULT_ACTIVE_CONFIG)
.setId(mActiveModeId)
+ .setPhysicalDisplayId(PhysicalDisplayId(0))
.setWidth(FakeHwcDisplayInjector::DEFAULT_WIDTH)
.setHeight(FakeHwcDisplayInjector::DEFAULT_HEIGHT)
.setVsyncPeriod(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)
@@ -721,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&));