diff options
36 files changed, 735 insertions, 488 deletions
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index d51d34b3c5..8957e90034 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -399,8 +399,7 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { // Add this buffer from our internal queue tracker { // Autolock scope const nsecs_t presentTime = item.mIsAutoTimestamp ? 0 : item.mTimestamp; - const bool isHDR = item.mHdrMetadata.validTypes != 0; - mFlinger->mScheduler->recordLayerHistory(this, presentTime, isHDR); + mFlinger->mScheduler->recordLayerHistory(this, presentTime); Mutex::Autolock lock(mQueueItemLock); // Reset the frame number tracker when we receive the first buffer after diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index d68fe8e3a5..1e471e53ff 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -247,8 +247,7 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, nsecs_t postTi FrameTracer::FrameEvent::POST); mCurrentState.desiredPresentTime = desiredPresentTime; - const bool isHDR = mCurrentState.hdrMetadata.validTypes != 0; - mFlinger->mScheduler->recordLayerHistory(this, desiredPresentTime, isHDR); + mFlinger->mScheduler->recordLayerHistory(this, desiredPresentTime); return true; } diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 89123df46c..84ec597d2f 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -132,11 +132,11 @@ bool DisplayDevice::isPoweredOn() const { } // ---------------------------------------------------------------------------- -void DisplayDevice::setActiveConfig(int mode) { +void DisplayDevice::setActiveConfig(HwcConfigIndexType mode) { mActiveConfig = mode; } -int DisplayDevice::getActiveConfig() const { +HwcConfigIndexType DisplayDevice::getActiveConfig() const { return mActiveConfig; } @@ -285,7 +285,7 @@ void DisplayDevice::dump(std::string& result) const { result.append(" "); StringAppendF(&result, "powerMode=%d, ", mPowerMode); - StringAppendF(&result, "activeConfig=%d, ", mActiveConfig); + StringAppendF(&result, "activeConfig=%d, ", mActiveConfig.value()); getCompositionDisplay()->dump(result); } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index ce4e1e6b09..2d0875b0c5 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -43,6 +43,7 @@ #include "DisplayHardware/DisplayIdentification.h" #include "DisplayHardware/PowerAdvisor.h" #include "RenderArea.h" +#include "Scheduler/HwcStrongTypes.h" namespace android { @@ -141,8 +142,8 @@ public: /* ------------------------------------------------------------------------ * Display active config management. */ - int getActiveConfig() const; - void setActiveConfig(int mode); + HwcConfigIndexType getActiveConfig() const; + void setActiveConfig(HwcConfigIndexType mode); // release HWC resources (if any) for removable displays void disconnect(); @@ -186,7 +187,7 @@ private: // Current power mode int mPowerMode; // Current active config - int mActiveConfig; + HwcConfigIndexType mActiveConfig; // TODO(b/74619554): Remove special cases for primary display. const bool mIsPrimary; diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 976fedb58a..38a80a798a 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -20,8 +20,6 @@ namespace android { -using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; - RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger) : mFlinger(flinger), mClient(new Client(&mFlinger)) { createLayer(); @@ -51,8 +49,8 @@ bool RefreshRateOverlay::createLayer() { return true; } -void RefreshRateOverlay::changeRefreshRate(RefreshRateType type) { - const half3& color = (type == RefreshRateType::PERFORMANCE) ? GREEN : RED; +void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) { + const half3& color = (refreshRate.fps > 65.0f) ? GREEN : RED; mLayer->setColor(color); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h index ce29bc3243..414bc47ac9 100644 --- a/services/surfaceflinger/RefreshRateOverlay.h +++ b/services/surfaceflinger/RefreshRateOverlay.h @@ -19,13 +19,13 @@ namespace android { -using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; +using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; class RefreshRateOverlay { public: RefreshRateOverlay(SurfaceFlinger& flinger); - void changeRefreshRate(RefreshRateType type); + void changeRefreshRate(const RefreshRate& refreshRate); private: bool createLayer(); diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 8d9adc8525..ff800c3dbf 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -36,6 +36,7 @@ #include <utils/Trace.h> #include "EventThread.h" +#include "HwcStrongTypes.h" using namespace std::chrono_literals; @@ -101,10 +102,11 @@ DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t times return event; } -DisplayEventReceiver::Event makeConfigChanged(PhysicalDisplayId displayId, int32_t configId) { +DisplayEventReceiver::Event makeConfigChanged(PhysicalDisplayId displayId, + HwcConfigIndexType configId) { DisplayEventReceiver::Event event; event.header = {DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, displayId, systemTime()}; - event.config.configId = configId; + event.config.configId = configId.value(); return event; } @@ -290,7 +292,7 @@ void EventThread::onHotplugReceived(PhysicalDisplayId displayId, bool connected) mCondition.notify_all(); } -void EventThread::onConfigChanged(PhysicalDisplayId displayId, int32_t configId) { +void EventThread::onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId) { std::lock_guard<std::mutex> lock(mMutex); mPendingEvents.push_back(makeConfigChanged(displayId, configId)); diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index a029586088..a42546c7df 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -33,6 +33,7 @@ #include <private/gui/BitTube.h> #include <utils/Errors.h> +#include "HwcStrongTypes.h" // --------------------------------------------------------------------------- namespace android { @@ -109,7 +110,7 @@ public: virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0; // called when SF changes the active config and apps needs to be notified about the change - virtual void onConfigChanged(PhysicalDisplayId displayId, int32_t configId) = 0; + virtual void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId) = 0; virtual void dump(std::string& result) const = 0; @@ -146,7 +147,7 @@ public: void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override; - void onConfigChanged(PhysicalDisplayId displayId, int32_t configId) override; + void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId) override; void dump(std::string& result) const override; diff --git a/services/surfaceflinger/Scheduler/HwcStrongTypes.h b/services/surfaceflinger/Scheduler/HwcStrongTypes.h new file mode 100644 index 0000000000..cfbbdfe4fd --- /dev/null +++ b/services/surfaceflinger/Scheduler/HwcStrongTypes.h @@ -0,0 +1,27 @@ +/* + * Copyright 2019 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 "StrongTyping.h" + +namespace android { + +// Strong types for the different indexes as they are referring to a different base. +using HwcConfigIndexType = StrongTyping<int, struct HwcConfigIndexTypeTag, Compare, Add, Hash>; +using HwcConfigGroupType = StrongTyping<int, struct HwcConfigGroupTypeTag, Compare>; + +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 8b717289c6..146ec1bce0 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -39,7 +39,7 @@ namespace android::scheduler { namespace { bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) { - return layer.isVisible() && (info.isHDR() || info.getLastUpdatedTime() >= threshold); + return layer.isVisible() && info.getLastUpdatedTime() >= threshold; } bool traceEnabled() { @@ -69,7 +69,7 @@ void LayerHistory::registerLayer(Layer* layer, float lowRefreshRate, float highR mLayerInfos.emplace_back(layer, std::move(info)); } -void LayerHistory::record(Layer* layer, nsecs_t presentTime, bool isHDR, nsecs_t now) { +void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now) { std::lock_guard lock(mLock); const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(), @@ -78,7 +78,6 @@ void LayerHistory::record(Layer* layer, nsecs_t presentTime, bool isHDR, nsecs_t const auto& info = it->second; info->setLastPresentTime(presentTime, now); - info->setIsHDR(isHDR); // Activate layer if inactive. if (const auto end = activeLayers().end(); it >= end) { @@ -89,7 +88,6 @@ void LayerHistory::record(Layer* layer, nsecs_t presentTime, bool isHDR, nsecs_t LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { float maxRefreshRate = 0; - bool isHDR = false; std::lock_guard lock(mLock); @@ -108,13 +106,12 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { trace(layer, std::round(refreshRate)); } } - isHDR |= info->isHDR(); } if (CC_UNLIKELY(mTraceEnabled)) { - ALOGD("%s: maxRefreshRate=%.2f, isHDR=%d", __FUNCTION__, maxRefreshRate, isHDR); + ALOGD("%s: maxRefreshRate=%.2f", __FUNCTION__, maxRefreshRate); } - return {maxRefreshRate, isHDR}; + return {maxRefreshRate}; } void LayerHistory::partitionLayers(nsecs_t now) { diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index bd9aca1aed..745c4c16ee 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -46,11 +46,10 @@ public: void registerLayer(Layer*, float lowRefreshRate, float highRefreshRate); // Marks the layer as active, and records the given state to its history. - void record(Layer*, nsecs_t presentTime, bool isHDR, nsecs_t now); + void record(Layer*, nsecs_t presentTime, nsecs_t now); struct Summary { float maxRefreshRate; // Maximum refresh rate among recently active layers. - bool isHDR; // True if any recently active layer has HDR content. }; // Rebuilds sets of active/inactive layers, and accumulates stats for active layers. diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index b86709fc9c..cb81ca2840 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -140,9 +140,6 @@ public: // updated time, the updated time is the present time. void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now); - bool isHDR() const { return mIsHDR; } - void setIsHDR(bool isHDR) { mIsHDR = isHDR; } - bool isRecentlyActive(nsecs_t now) const { return mPresentTimeHistory.isRecentlyActive(now); } bool isFrequent(nsecs_t now) const { return mPresentTimeHistory.isFrequent(now); } @@ -167,7 +164,6 @@ private: nsecs_t mLastPresentTime = 0; RefreshRateHistory mRefreshRateHistory{mHighRefreshRate}; PresentTimeHistory mPresentTimeHistory; - bool mIsHDR = false; }; } // namespace scheduler diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index 6be88f89f9..12832a690a 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -48,16 +48,18 @@ PhaseOffsets::PhaseOffsets() { getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns") .value_or(std::numeric_limits<nsecs_t>::max()); - const Offsets defaultOffsets = getDefaultOffsets(thresholdForNextVsync); - const Offsets highFpsOffsets = getHighFpsOffsets(thresholdForNextVsync); - - mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets}); - mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets}); + mDefaultOffsets = getDefaultOffsets(thresholdForNextVsync); + mHighFpsOffsets = getHighFpsOffsets(thresholdForNextVsync); } -PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate( - RefreshRateType refreshRateType) const { - return mOffsets.at(refreshRateType); +PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(float fps) const { + // TODO(145561086): Once offsets are common for all refresh rates we can remove the magic + // number for refresh rate + if (fps > 65.0f) { + return mHighFpsOffsets; + } else { + return mDefaultOffsets; + } } void PhaseOffsets::dump(std::string& result) const { @@ -80,13 +82,13 @@ PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t thresholdForNextVs const auto earlyAppOffsetNs = getProperty("debug.sf.early_app_phase_offset_ns"); const auto earlyGlAppOffsetNs = getProperty("debug.sf.early_gl_app_phase_offset_ns"); - return {{RefreshRateType::DEFAULT, earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs), + return {{earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs), earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs)}, - {RefreshRateType::DEFAULT, earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs), + {earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs), earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs)}, - {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}, + {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}, thresholdForNextVsync}; } @@ -104,13 +106,13 @@ PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t thresholdForNextVs const auto highFpsEarlyGlAppOffsetNs = getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns"); - return {{RefreshRateType::PERFORMANCE, highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs), + return {{highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs), highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs)}, - {RefreshRateType::PERFORMANCE, highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs), + {highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs), highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs)}, - {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}, + {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}, thresholdForNextVsync}; } diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h index 2c52432448..7747f0cfcc 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.h +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h @@ -32,7 +32,6 @@ namespace android::scheduler { class PhaseOffsets { public: using Offsets = VSyncModulator::OffsetsConfig; - using RefreshRateType = RefreshRateConfigs::RefreshRateType; virtual ~PhaseOffsets(); @@ -43,9 +42,9 @@ public: } virtual Offsets getCurrentOffsets() const = 0; - virtual Offsets getOffsetsForRefreshRate(RefreshRateType) const = 0; + virtual Offsets getOffsetsForRefreshRate(float fps) const = 0; - virtual void setRefreshRateType(RefreshRateType) = 0; + virtual void setRefreshRateFps(float fps) = 0; virtual void dump(std::string& result) const = 0; }; @@ -57,18 +56,14 @@ public: PhaseOffsets(); // Returns early, early GL, and late offsets for Apps and SF for a given refresh rate. - Offsets getOffsetsForRefreshRate(RefreshRateType) const override; + Offsets getOffsetsForRefreshRate(float fps) const override; // Returns early, early GL, and late offsets for Apps and SF. - Offsets getCurrentOffsets() const override { - return getOffsetsForRefreshRate(mRefreshRateType); - } + Offsets getCurrentOffsets() const override { return getOffsetsForRefreshRate(mRefreshRateFps); } // This function should be called when the device is switching between different // refresh rates, to properly update the offsets. - void setRefreshRateType(RefreshRateType refreshRateType) override { - mRefreshRateType = refreshRateType; - } + void setRefreshRateFps(float fps) override { mRefreshRateFps = fps; } // Returns current offsets in human friendly format. void dump(std::string& result) const override; @@ -77,9 +72,10 @@ private: static Offsets getDefaultOffsets(nsecs_t thresholdForNextVsync); static Offsets getHighFpsOffsets(nsecs_t thresholdForNextVsync); - std::atomic<RefreshRateType> mRefreshRateType = RefreshRateType::DEFAULT; + std::atomic<float> mRefreshRateFps = 0; - std::unordered_map<RefreshRateType, Offsets> mOffsets; + Offsets mDefaultOffsets; + Offsets mHighFpsOffsets; }; } // namespace impl diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 7dc98cce94..23fb96a38b 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -13,135 +13,169 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +// #define LOG_NDEBUG 0 #include "RefreshRateConfigs.h" namespace android::scheduler { + +using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType; using RefreshRate = RefreshRateConfigs::RefreshRate; -using RefreshRateType = RefreshRateConfigs::RefreshRateType; // Returns the refresh rate map. This map won't be modified at runtime, so it's safe to access // from multiple threads. This can only be called if refreshRateSwitching() returns true. // TODO(b/122916473): Get this information from configs prepared by vendors, instead of // baking them in. -const std::map<RefreshRateType, RefreshRate>& RefreshRateConfigs::getRefreshRateMap() const { - LOG_ALWAYS_FATAL_IF(!mRefreshRateSwitchingSupported); - return mRefreshRateMap; -} - -const RefreshRate& RefreshRateConfigs::getRefreshRateFromType(RefreshRateType type) const { - if (!mRefreshRateSwitchingSupported) { - return getCurrentRefreshRate().second; - } else { - auto refreshRate = mRefreshRateMap.find(type); - LOG_ALWAYS_FATAL_IF(refreshRate == mRefreshRateMap.end()); - return refreshRate->second; - } -} - -std::pair<RefreshRateType, const RefreshRate&> RefreshRateConfigs::getCurrentRefreshRate() const { - int currentConfig = mCurrentConfig; - if (mRefreshRateSwitchingSupported) { - for (const auto& [type, refresh] : mRefreshRateMap) { - if (refresh.configId == currentConfig) { - return {type, refresh}; +const RefreshRate& RefreshRateConfigs::getRefreshRateForContent(float contentFramerate) const { + std::lock_guard lock(mLock); + // Find the appropriate refresh rate with minimal error + auto iter = min_element(mAvailableRefreshRates.cbegin(), mAvailableRefreshRates.cend(), + [contentFramerate](const auto& lhs, const auto& rhs) -> bool { + return std::abs(lhs->fps - contentFramerate) < + std::abs(rhs->fps - contentFramerate); + }); + + // Some content aligns better on higher refresh rate. For example for 45fps we should choose + // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't + // align well with both + const RefreshRate* bestSoFar = *iter; + constexpr float MARGIN = 0.05f; + float ratio = (*iter)->fps / contentFramerate; + if (std::abs(std::round(ratio) - ratio) > MARGIN) { + while (iter != mAvailableRefreshRates.cend()) { + ratio = (*iter)->fps / contentFramerate; + + if (std::abs(std::round(ratio) - ratio) <= MARGIN) { + bestSoFar = *iter; + break; } + ++iter; } - LOG_ALWAYS_FATAL(); } - return {RefreshRateType::DEFAULT, mRefreshRates[currentConfig]}; + + return *bestSoFar; } -const RefreshRate& RefreshRateConfigs::getRefreshRateFromConfigId(int configId) const { - LOG_ALWAYS_FATAL_IF(configId >= mRefreshRates.size()); - return mRefreshRates[configId]; +const AllRefreshRatesMapType& RefreshRateConfigs::getAllRefreshRates() const { + return mRefreshRates; } -RefreshRateType RefreshRateConfigs::getRefreshRateTypeFromHwcConfigId(hwc2_config_t hwcId) const { - if (!mRefreshRateSwitchingSupported) return RefreshRateType::DEFAULT; +const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const { + std::lock_guard lock(mLock); + if (!mRefreshRateSwitching) { + return *mCurrentRefreshRate; + } else { + return *mAvailableRefreshRates.front(); + } +} - for (const auto& [type, refreshRate] : mRefreshRateMap) { - if (refreshRate.hwcId == hwcId) { - return type; - } +const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const { + std::lock_guard lock(mLock); + if (!mRefreshRateSwitching) { + return *mCurrentRefreshRate; + } else { + return *mAvailableRefreshRates.back(); } +} - return RefreshRateType::DEFAULT; +const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const { + std::lock_guard lock(mLock); + return *mCurrentRefreshRate; } -void RefreshRateConfigs::setCurrentConfig(int config) { - LOG_ALWAYS_FATAL_IF(config >= mRefreshRates.size()); - mCurrentConfig = config; +void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) { + std::lock_guard lock(mLock); + mCurrentRefreshRate = &mRefreshRates.at(configId); } RefreshRateConfigs::RefreshRateConfigs(bool refreshRateSwitching, - const std::vector<InputConfig>& configs, int currentConfig) { - init(refreshRateSwitching, configs, currentConfig); + const std::vector<InputConfig>& configs, + HwcConfigIndexType currentHwcConfig) + : mRefreshRateSwitching(refreshRateSwitching) { + init(configs, currentHwcConfig); } RefreshRateConfigs::RefreshRateConfigs( bool refreshRateSwitching, const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs, - int currentConfig) { + HwcConfigIndexType currentConfigId) + : mRefreshRateSwitching(refreshRateSwitching) { std::vector<InputConfig> inputConfigs; - for (const auto& config : configs) { - inputConfigs.push_back({config->getId(), config->getVsyncPeriod()}); + for (auto configId = HwcConfigIndexType(0); configId < HwcConfigIndexType(configs.size()); + ++configId) { + auto configGroup = HwcConfigGroupType(configs[configId.value()]->getConfigGroup()); + inputConfigs.push_back( + {configId, configGroup, configs[configId.value()]->getVsyncPeriod()}); } - init(refreshRateSwitching, inputConfigs, currentConfig); + init(inputConfigs, currentConfigId); } -void RefreshRateConfigs::init(bool refreshRateSwitching, const std::vector<InputConfig>& configs, - int currentConfig) { - mRefreshRateSwitchingSupported = refreshRateSwitching; - LOG_ALWAYS_FATAL_IF(configs.empty()); - LOG_ALWAYS_FATAL_IF(currentConfig >= configs.size()); - mCurrentConfig = currentConfig; - - auto buildRefreshRate = [&](int configId) -> RefreshRate { - const nsecs_t vsyncPeriod = configs[configId].vsyncPeriod; - const float fps = 1e9 / vsyncPeriod; - return {configId, base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps), - vsyncPeriod, configs[configId].hwcId}; - }; +void RefreshRateConfigs::setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate, + float maxRefreshRate) { + std::lock_guard lock(mLock); + mCurrentGroupId = mRefreshRates.at(defaultConfigId).configGroup; + mMinRefreshRateFps = minRefreshRate; + mMaxRefreshRateFps = maxRefreshRate; + constructAvailableRefreshRates(); +} - for (int i = 0; i < configs.size(); ++i) { - mRefreshRates.push_back(buildRefreshRate(i)); +void RefreshRateConfigs::getSortedRefreshRateList( + const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate, + std::vector<const RefreshRate*>* outRefreshRates) { + outRefreshRates->clear(); + outRefreshRates->reserve(mRefreshRates.size()); + for (const auto& [type, refreshRate] : mRefreshRates) { + if (shouldAddRefreshRate(refreshRate)) { + ALOGV("getSortedRefreshRateList: config %d added to list policy", + refreshRate.configId.value()); + outRefreshRates->push_back(&refreshRate); + } } - if (!mRefreshRateSwitchingSupported) return; + std::sort(outRefreshRates->begin(), outRefreshRates->end(), + [](const auto refreshRate1, const auto refreshRate2) { + return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod; + }); +} - auto findDefaultAndPerfConfigs = [&]() -> std::optional<std::pair<int, int>> { - if (configs.size() < 2) { - return {}; - } +void RefreshRateConfigs::constructAvailableRefreshRates() { + // Filter configs based on current policy and sort based on vsync period + ALOGV("constructRefreshRateMap: group %d min %.2f max %.2f", mCurrentGroupId.value(), + mMinRefreshRateFps, mMaxRefreshRateFps); + getSortedRefreshRateList( + [this](const RefreshRate& refreshRate) REQUIRES(mLock) { + return refreshRate.configGroup == mCurrentGroupId && + refreshRate.fps >= mMinRefreshRateFps && + refreshRate.fps <= mMaxRefreshRateFps; + }, + &mAvailableRefreshRates); +} - std::vector<const RefreshRate*> sortedRefreshRates; - for (const auto& refreshRate : mRefreshRates) { - sortedRefreshRates.push_back(&refreshRate); - } - std::sort(sortedRefreshRates.begin(), sortedRefreshRates.end(), - [](const RefreshRate* refreshRate1, const RefreshRate* refreshRate2) { - return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod; - }); - - // When the configs are ordered by the resync rate, we assume that - // the first one is DEFAULT and the second one is PERFORMANCE, - // i.e. the higher rate. - if (sortedRefreshRates[0]->vsyncPeriod == 0 || sortedRefreshRates[1]->vsyncPeriod == 0) { - return {}; - } +// NO_THREAD_SAFETY_ANALYSIS since this is called from the constructor +void RefreshRateConfigs::init(const std::vector<InputConfig>& configs, + HwcConfigIndexType currentHwcConfig) NO_THREAD_SAFETY_ANALYSIS { + LOG_ALWAYS_FATAL_IF(configs.empty()); + LOG_ALWAYS_FATAL_IF(currentHwcConfig.value() >= configs.size()); - return std::pair<int, int>(sortedRefreshRates[0]->configId, - sortedRefreshRates[1]->configId); + auto buildRefreshRate = [&](InputConfig config) -> RefreshRate { + const float fps = 1e9f / config.vsyncPeriod; + return RefreshRate(config.configId, config.vsyncPeriod, config.configGroup, + base::StringPrintf("%2.ffps", fps), fps); }; - auto defaultAndPerfConfigs = findDefaultAndPerfConfigs(); - if (!defaultAndPerfConfigs) { - mRefreshRateSwitchingSupported = false; - return; + for (const auto& config : configs) { + mRefreshRates.emplace(config.configId, buildRefreshRate(config)); + if (config.configId == currentHwcConfig) { + mCurrentRefreshRate = &mRefreshRates.at(config.configId); + mCurrentGroupId = config.configGroup; + } } - mRefreshRateMap[RefreshRateType::DEFAULT] = mRefreshRates[defaultAndPerfConfigs->first]; - mRefreshRateMap[RefreshRateType::PERFORMANCE] = mRefreshRates[defaultAndPerfConfigs->second]; + std::vector<const RefreshRate*> sortedConfigs; + getSortedRefreshRateList([](const RefreshRate&) { return true; }, &sortedConfigs); + mMinSupportedRefreshRate = sortedConfigs.front(); + mMaxSupportedRefreshRate = sortedConfigs.back(); + constructAvailableRefreshRates(); } -} // namespace android::scheduler
\ No newline at end of file +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 90bba24332..fb14dc7a9a 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -23,7 +23,9 @@ #include <type_traits> #include "DisplayHardware/HWComposer.h" +#include "HwcStrongTypes.h" #include "Scheduler/SchedulerUtils.h" +#include "Scheduler/StrongTyping.h" namespace android::scheduler { @@ -41,71 +43,123 @@ inline RefreshRateConfigEvent operator|(RefreshRateConfigEvent lhs, RefreshRateC */ class RefreshRateConfigs { public: - // Enum to indicate which vsync rate to run at. Default is the old 60Hz, and performance - // is the new 90Hz. Eventually we want to have a way for vendors to map these in the configs. - enum class RefreshRateType { DEFAULT, PERFORMANCE }; - struct RefreshRate { + RefreshRate(HwcConfigIndexType configId, nsecs_t vsyncPeriod, + HwcConfigGroupType configGroup, std::string name, float fps) + : configId(configId), + vsyncPeriod(vsyncPeriod), + configGroup(configGroup), + name(std::move(name)), + fps(fps) {} // This config ID corresponds to the position of the config in the vector that is stored // on the device. - int configId; - // Human readable name of the refresh rate. - std::string name; - // Refresh rate in frames per second, rounded to the nearest integer. - uint32_t fps = 0; + const HwcConfigIndexType configId; // Vsync period in nanoseconds. - nsecs_t vsyncPeriod; - // Hwc config Id (returned from HWC2::Display::Config::getId()) - hwc2_config_t hwcId; + const nsecs_t vsyncPeriod; + // This configGroup for the config. + const HwcConfigGroupType configGroup; + // Human readable name of the refresh rate. + const std::string name; + // Refresh rate in frames per second + const float fps = 0; + + bool operator!=(const RefreshRate& other) const { + return configId != other.configId || vsyncPeriod != other.vsyncPeriod || + configGroup != other.configGroup; + } + + bool operator==(const RefreshRate& other) const { return !(*this != other); } }; + using AllRefreshRatesMapType = std::unordered_map<HwcConfigIndexType, const RefreshRate>; + + // Sets the current policy to choose refresh rates. + void setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate, float maxRefreshRate) + EXCLUDES(mLock); + // Returns true if this device is doing refresh rate switching. This won't change at runtime. - bool refreshRateSwitchingSupported() const { return mRefreshRateSwitchingSupported; } + bool refreshRateSwitchingSupported() const { return mRefreshRateSwitching; } + + // Returns all available refresh rates according to the current policy. + const RefreshRate& getRefreshRateForContent(float contentFramerate) const EXCLUDES(mLock); + + // Returns all the refresh rates supported by the device. This won't change at runtime. + const AllRefreshRatesMapType& getAllRefreshRates() const EXCLUDES(mLock); - // Returns the refresh rate map. This map won't be modified at runtime, so it's safe to access - // from multiple threads. This can only be called if refreshRateSwitching() returns true. - // TODO(b/122916473): Get this information from configs prepared by vendors, instead of - // baking them in. - const std::map<RefreshRateType, RefreshRate>& getRefreshRateMap() const; + // Returns the lowest refresh rate supported by the device. This won't change at runtime. + const RefreshRate& getMinRefreshRate() const { return *mMinSupportedRefreshRate; } - const RefreshRate& getRefreshRateFromType(RefreshRateType type) const; + // Returns the lowest refresh rate according to the current policy. May change in runtime. + const RefreshRate& getMinRefreshRateByPolicy() const EXCLUDES(mLock); - std::pair<RefreshRateType, const RefreshRate&> getCurrentRefreshRate() const; + // Returns the highest refresh rate supported by the device. This won't change at runtime. + const RefreshRate& getMaxRefreshRate() const { return *mMaxSupportedRefreshRate; } - const RefreshRate& getRefreshRateFromConfigId(int configId) const; + // Returns the highest refresh rate according to the current policy. May change in runtime. + const RefreshRate& getMaxRefreshRateByPolicy() const EXCLUDES(mLock); - RefreshRateType getRefreshRateTypeFromHwcConfigId(hwc2_config_t hwcId) const; + // Returns the current refresh rate + const RefreshRate& getCurrentRefreshRate() const EXCLUDES(mLock); - void setCurrentConfig(int config); + // Returns the refresh rate that corresponds to a HwcConfigIndexType. This won't change at + // runtime. + const RefreshRate& getRefreshRateFromConfigId(HwcConfigIndexType configId) const { + return mRefreshRates.at(configId); + }; + + // Stores the current configId the device operates at + void setCurrentConfigId(HwcConfigIndexType configId) EXCLUDES(mLock); struct InputConfig { - hwc2_config_t hwcId = 0; + HwcConfigIndexType configId = HwcConfigIndexType(0); + HwcConfigGroupType configGroup = HwcConfigGroupType(0); nsecs_t vsyncPeriod = 0; }; RefreshRateConfigs(bool refreshRateSwitching, const std::vector<InputConfig>& configs, - int currentConfig); - + HwcConfigIndexType currentHwcConfig); RefreshRateConfigs(bool refreshRateSwitching, const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs, - int currentConfig); + HwcConfigIndexType currentConfigId); private: - void init(bool refreshRateSwitching, const std::vector<InputConfig>& configs, - int currentConfig); - // Whether this device is doing refresh rate switching or not. This must not change after this - // object is initialized. - bool mRefreshRateSwitchingSupported; + void init(const std::vector<InputConfig>& configs, HwcConfigIndexType currentHwcConfig); + + void constructAvailableRefreshRates() REQUIRES(mLock); + + void getSortedRefreshRateList( + const std::function<bool(const RefreshRate&)>& shouldAddRefreshRate, + std::vector<const RefreshRate*>* outRefreshRates); + // The list of refresh rates, indexed by display config ID. This must not change after this // object is initialized. - std::vector<RefreshRate> mRefreshRates; - // The mapping of refresh rate type to RefreshRate. This must not change after this object is - // initialized. - std::map<RefreshRateType, RefreshRate> mRefreshRateMap; - // The ID of the current config. This will change at runtime. This is set by SurfaceFlinger on - // the main thread, and read by the Scheduler (and other objects) on other threads, so it's - // atomic. - std::atomic<int> mCurrentConfig; + AllRefreshRatesMapType mRefreshRates; + + // The list of refresh rates which are available in the current policy, ordered by vsyncPeriod + // (the first element is the lowest refresh rate) + std::vector<const RefreshRate*> mAvailableRefreshRates GUARDED_BY(mLock); + + // The current config. This will change at runtime. This is set by SurfaceFlinger on + // the main thread, and read by the Scheduler (and other objects) on other threads. + const RefreshRate* mCurrentRefreshRate GUARDED_BY(mLock); + + // The current config group. This will change at runtime. This is set by SurfaceFlinger on + // the main thread, and read by the Scheduler (and other objects) on other threads. + HwcConfigGroupType mCurrentGroupId GUARDED_BY(mLock); + + // The min and max FPS allowed by the policy. This will change at runtime and set by + // SurfaceFlinger on the main thread. + float mMinRefreshRateFps GUARDED_BY(mLock) = 0; + float mMaxRefreshRateFps GUARDED_BY(mLock) = std::numeric_limits<float>::max(); + + // The min and max refresh rates supported by the device. + // This will not change at runtime. + const RefreshRate* mMinSupportedRefreshRate; + const RefreshRate* mMaxSupportedRefreshRate; + + const bool mRefreshRateSwitching; + + mutable std::mutex mLock; }; } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h index 8afc93e8db..a384dbe29b 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateStats.h +++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h @@ -25,8 +25,7 @@ #include "android-base/stringprintf.h" #include "utils/Timers.h" -namespace android { -namespace scheduler { +namespace android::scheduler { /** * Class to encapsulate statistics about refresh rates that the display is using. When the power @@ -42,10 +41,10 @@ class RefreshRateStats { public: RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats, - int currentConfigMode, int currentPowerMode) + HwcConfigIndexType currentConfigId, int currentPowerMode) : mRefreshRateConfigs(refreshRateConfigs), mTimeStats(timeStats), - mCurrentConfigMode(currentConfigMode), + mCurrentConfigMode(currentConfigId), mCurrentPowerMode(currentPowerMode) {} // Sets power mode. @@ -59,12 +58,12 @@ public: // Sets config mode. If the mode has changed, it records how much time was spent in the previous // mode. - void setConfigMode(int mode) { - if (mCurrentConfigMode == mode) { + void setConfigMode(HwcConfigIndexType configId) { + if (mCurrentConfigMode == configId) { return; } flushTime(); - mCurrentConfigMode = mode; + mCurrentConfigMode = configId; } // Returns a map between human readable refresh rate and number of seconds the device spent in @@ -78,11 +77,11 @@ public: std::unordered_map<std::string, int64_t> totalTime; // Multiple configs may map to the same name, e.g. "60fps". Add the // times for such configs together. - for (const auto& [config, time] : mConfigModesTotalTime) { - totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(config).name] = 0; + for (const auto& [configId, time] : mConfigModesTotalTime) { + totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(configId).name] = 0; } - for (const auto& [config, time] : mConfigModesTotalTime) { - totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(config).name] += time; + for (const auto& [configId, time] : mConfigModesTotalTime) { + totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(configId).name] += time; } totalTime["ScreenOff"] = mScreenOffTime; return totalTime; @@ -139,14 +138,14 @@ private: // Aggregate refresh rate statistics for telemetry. TimeStats& mTimeStats; - int mCurrentConfigMode; + HwcConfigIndexType mCurrentConfigMode; int32_t mCurrentPowerMode; - std::unordered_map<int /* config */, int64_t /* duration in ms */> mConfigModesTotalTime; + std::unordered_map<HwcConfigIndexType /* configId */, int64_t /* duration in ms */> + mConfigModesTotalTime; int64_t mScreenOffTime = 0; nsecs_t mPreviousRecordedTime = systemTime(); }; -} // namespace scheduler -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 55fd6032f2..1d50fe1dd4 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -182,7 +182,7 @@ void Scheduler::onScreenReleased(ConnectionHandle handle) { } void Scheduler::onConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId, - int32_t configId) { + HwcConfigIndexType configId) { RETURN_IF_INVALID_HANDLE(handle); mConnections[handle].thread->onConfigChanged(displayId, configId); } @@ -280,8 +280,7 @@ void Scheduler::resync() { const nsecs_t last = mLastResyncTime.exchange(now); if (now - last > kIgnoreDelay) { - resyncToHardwareVsync(false, - mRefreshRateConfigs.getCurrentRefreshRate().second.vsyncPeriod); + resyncToHardwareVsync(false, mRefreshRateConfigs.getCurrentRefreshRate().vsyncPeriod); } } @@ -332,53 +331,49 @@ nsecs_t Scheduler::getDispSyncExpectedPresentTime() { void Scheduler::registerLayer(Layer* layer) { if (!mLayerHistory) return; - const auto type = layer->getWindowType() == InputWindowInfo::TYPE_WALLPAPER - ? RefreshRateType::DEFAULT - : RefreshRateType::PERFORMANCE; - - const auto lowFps = mRefreshRateConfigs.getRefreshRateFromType(RefreshRateType::DEFAULT).fps; - const auto highFps = mRefreshRateConfigs.getRefreshRateFromType(type).fps; + const auto lowFps = mRefreshRateConfigs.getMinRefreshRate().fps; + const auto highFps = layer->getWindowType() == InputWindowInfo::TYPE_WALLPAPER + ? lowFps + : mRefreshRateConfigs.getMaxRefreshRate().fps; mLayerHistory->registerLayer(layer, lowFps, highFps); } -void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime, bool isHDR) { +void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime) { if (mLayerHistory) { - mLayerHistory->record(layer, presentTime, isHDR, systemTime()); + mLayerHistory->record(layer, presentTime, systemTime()); } } void Scheduler::chooseRefreshRateForContent() { if (!mLayerHistory) return; - auto [refreshRate, isHDR] = mLayerHistory->summarize(systemTime()); + auto [refreshRate] = mLayerHistory->summarize(systemTime()); const uint32_t refreshRateRound = std::round(refreshRate); - RefreshRateType newRefreshRateType; + HwcConfigIndexType newConfigId; { std::lock_guard<std::mutex> lock(mFeatureStateLock); - if (mFeatures.contentRefreshRate == refreshRateRound && mFeatures.isHDRContent == isHDR) { + if (mFeatures.contentRefreshRate == refreshRateRound) { return; } mFeatures.contentRefreshRate = refreshRateRound; ATRACE_INT("ContentFPS", refreshRateRound); - mFeatures.isHDRContent = isHDR; - ATRACE_INT("ContentHDR", isHDR); - mFeatures.contentDetection = refreshRateRound > 0 ? ContentDetectionState::On : ContentDetectionState::Off; - newRefreshRateType = calculateRefreshRateType(); - if (mFeatures.refreshRateType == newRefreshRateType) { + newConfigId = calculateRefreshRateType(); + if (mFeatures.configId == newConfigId) { return; } - mFeatures.refreshRateType = newRefreshRateType; - } - changeRefreshRate(newRefreshRateType, ConfigEvent::Changed); + mFeatures.configId = newConfigId; + }; + auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId); + changeRefreshRate(newRefreshRate, ConfigEvent::Changed); } -void Scheduler::setChangeRefreshRateCallback(ChangeRefreshRateCallback&& callback) { +void Scheduler::setSchedulerCallback(android::Scheduler::ISchedulerCallback* callback) { std::lock_guard<std::mutex> lock(mCallbackLock); - mChangeRefreshRateCallback = std::move(callback); + mSchedulerCallback = callback; } void Scheduler::resetIdleTimer() { @@ -423,13 +418,16 @@ void Scheduler::setDisplayPowerState(bool normal) { void Scheduler::kernelIdleTimerCallback(TimerState state) { ATRACE_INT("ExpiredKernelIdleTimer", static_cast<int>(state)); + // TODO(145561154): cleanup the kernel idle timer implementation and the refresh rate + // magic number const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate(); - if (state == TimerState::Reset && refreshRate.first == RefreshRateType::PERFORMANCE) { + constexpr float FPS_THRESHOLD_FOR_KERNEL_TIMER = 65.0f; + if (state == TimerState::Reset && refreshRate.fps > FPS_THRESHOLD_FOR_KERNEL_TIMER) { // If we're not in performance mode then the kernel timer shouldn't do // anything, as the refresh rate during DPU power collapse will be the // same. - resyncToHardwareVsync(true /* makeAvailable */, refreshRate.second.vsyncPeriod); - } else if (state == TimerState::Expired && refreshRate.first != RefreshRateType::PERFORMANCE) { + resyncToHardwareVsync(true /* makeAvailable */, refreshRate.vsyncPeriod); + } else if (state == TimerState::Expired && refreshRate.fps <= FPS_THRESHOLD_FOR_KERNEL_TIMER) { // Disable HW VSYNC if the timer expired, as we don't need it enabled if // we're not pushing frames, and if we're in PERFORMANCE mode then we'll // need to update the DispSync model anyway. @@ -471,96 +469,67 @@ void Scheduler::dump(std::string& result) const { template <class T> void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) { ConfigEvent event = ConfigEvent::None; - RefreshRateType newRefreshRateType; + HwcConfigIndexType newConfigId; { std::lock_guard<std::mutex> lock(mFeatureStateLock); if (*currentState == newState) { return; } *currentState = newState; - newRefreshRateType = calculateRefreshRateType(); - if (mFeatures.refreshRateType == newRefreshRateType) { + newConfigId = calculateRefreshRateType(); + if (mFeatures.configId == newConfigId) { return; } - mFeatures.refreshRateType = newRefreshRateType; + mFeatures.configId = newConfigId; if (eventOnContentDetection && mFeatures.contentDetection == ContentDetectionState::On) { event = ConfigEvent::Changed; } } - changeRefreshRate(newRefreshRateType, event); + const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId); + changeRefreshRate(newRefreshRate, event); } -Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { +HwcConfigIndexType Scheduler::calculateRefreshRateType() { if (!mRefreshRateConfigs.refreshRateSwitchingSupported()) { - return RefreshRateType::DEFAULT; - } - - // HDR content is not supported on PERFORMANCE mode - if (mForceHDRContentToDefaultRefreshRate && mFeatures.isHDRContent) { - return RefreshRateType::DEFAULT; + return mRefreshRateConfigs.getCurrentRefreshRate().configId; } // If Display Power is not in normal operation we want to be in performance mode. // When coming back to normal mode, a grace period is given with DisplayPowerTimer if (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset) { - return RefreshRateType::PERFORMANCE; + return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId; } // As long as touch is active we want to be in performance mode if (mFeatures.touch == TouchState::Active) { - return RefreshRateType::PERFORMANCE; + return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId; } // If timer has expired as it means there is no new content on the screen if (mFeatures.idleTimer == TimerState::Expired) { - return RefreshRateType::DEFAULT; + return mRefreshRateConfigs.getMinRefreshRateByPolicy().configId; } // If content detection is off we choose performance as we don't know the content fps if (mFeatures.contentDetection == ContentDetectionState::Off) { - return RefreshRateType::PERFORMANCE; + return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId; } // Content detection is on, find the appropriate refresh rate with minimal error - // TODO(b/139751853): Scan allowed refresh rates only (SurfaceFlinger::mAllowedDisplayConfigs) - const float rate = static_cast<float>(mFeatures.contentRefreshRate); - auto iter = min_element(mRefreshRateConfigs.getRefreshRateMap().cbegin(), - mRefreshRateConfigs.getRefreshRateMap().cend(), - [rate](const auto& lhs, const auto& rhs) -> bool { - return std::abs(lhs.second.fps - rate) < - std::abs(rhs.second.fps - rate); - }); - RefreshRateType currRefreshRateType = iter->first; - - // Some content aligns better on higher refresh rate. For example for 45fps we should choose - // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't - // align well with both - constexpr float MARGIN = 0.05f; - float ratio = mRefreshRateConfigs.getRefreshRateFromType(currRefreshRateType).fps / rate; - if (std::abs(std::round(ratio) - ratio) > MARGIN) { - while (iter != mRefreshRateConfigs.getRefreshRateMap().cend()) { - ratio = iter->second.fps / rate; - - if (std::abs(std::round(ratio) - ratio) <= MARGIN) { - currRefreshRateType = iter->first; - break; - } - ++iter; - } - } - - return currRefreshRateType; + return mRefreshRateConfigs + .getRefreshRateForContent(static_cast<float>(mFeatures.contentRefreshRate)) + .configId; } -Scheduler::RefreshRateType Scheduler::getPreferredRefreshRateType() { +std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() { std::lock_guard<std::mutex> lock(mFeatureStateLock); - return mFeatures.refreshRateType; + return mFeatures.configId; } -void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) { +void Scheduler::changeRefreshRate(const RefreshRate& refreshRate, ConfigEvent configEvent) { std::lock_guard<std::mutex> lock(mCallbackLock); - if (mChangeRefreshRateCallback) { - mChangeRefreshRateCallback(refreshRateType, configEvent); + if (mSchedulerCallback) { + mSchedulerCallback->changeRefreshRate(refreshRate, configEvent); } } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 346896c44f..04a83906b1 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -34,6 +34,8 @@ namespace android { +using namespace std::chrono_literals; + class DispSync; class FenceTime; class InjectVSyncSource; @@ -41,10 +43,14 @@ struct DisplayStateInfo; class Scheduler { public: - using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; + using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using ConfigEvent = scheduler::RefreshRateConfigEvent; - using ChangeRefreshRateCallback = std::function<void(RefreshRateType, ConfigEvent)>; + class ISchedulerCallback { + public: + virtual ~ISchedulerCallback() = default; + virtual void changeRefreshRate(const RefreshRate&, ConfigEvent) = 0; + }; // Indicates whether to start the transaction early, or at vsync time. enum class TransactionStart { EARLY, NORMAL }; @@ -67,7 +73,7 @@ public: sp<EventThreadConnection> getEventConnection(ConnectionHandle); void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected); - void onConfigChanged(ConnectionHandle, PhysicalDisplayId, int32_t configId); + void onConfigChanged(ConnectionHandle, PhysicalDisplayId, HwcConfigIndexType configId); void onScreenAcquired(ConnectionHandle); void onScreenReleased(ConnectionHandle); @@ -103,13 +109,13 @@ public: // Layers are registered on creation, and unregistered when the weak reference expires. void registerLayer(Layer*); - void recordLayerHistory(Layer*, nsecs_t presentTime, bool isHDR); + void recordLayerHistory(Layer*, nsecs_t presentTime); // Detects content using layer history, and selects a matching refresh rate. void chooseRefreshRateForContent(); - // Called by Scheduler to change refresh rate. - void setChangeRefreshRateCallback(ChangeRefreshRateCallback&&); + // Called by Scheduler to control SurfaceFlinger operations. + void setSchedulerCallback(ISchedulerCallback*); bool isIdleTimerEnabled() const { return mIdleTimer.has_value(); } void resetIdleTimer(); @@ -122,8 +128,8 @@ public: void dump(std::string&) const; void dump(ConnectionHandle, std::string&) const; - // Get the appropriate refresh type for current conditions. - RefreshRateType getPreferredRefreshRateType(); + // Get the appropriate refresh for current conditions. + std::optional<HwcConfigIndexType> getPreferredConfigId(); private: friend class TestableScheduler; @@ -158,9 +164,9 @@ private: void setVsyncPeriod(nsecs_t period); - RefreshRateType calculateRefreshRateType() REQUIRES(mFeatureStateLock); + HwcConfigIndexType calculateRefreshRateType() REQUIRES(mFeatureStateLock); // Acquires a lock and calls the ChangeRefreshRateCallback with given parameters. - void changeRefreshRate(RefreshRateType, ConfigEvent); + void changeRefreshRate(const RefreshRate&, ConfigEvent); // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection. struct Connection { @@ -198,7 +204,7 @@ private: std::optional<scheduler::OneShotTimer> mDisplayPowerTimer; std::mutex mCallbackLock; - ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock); + ISchedulerCallback* mSchedulerCallback GUARDED_BY(mCallbackLock) = nullptr; // In order to make sure that the features don't override themselves, we need a state machine // to keep track which feature requested the config change. @@ -210,17 +216,13 @@ private: TouchState touch = TouchState::Inactive; TimerState displayPowerTimer = TimerState::Expired; - RefreshRateType refreshRateType = RefreshRateType::DEFAULT; + std::optional<HwcConfigIndexType> configId; uint32_t contentRefreshRate = 0; - bool isHDRContent = false; bool isDisplayPowerStateNormal = true; } mFeatures GUARDED_BY(mFeatureStateLock); const scheduler::RefreshRateConfigs& mRefreshRateConfigs; - - // Global config to force HDR content to work on DEFAULT refreshRate - static constexpr bool mForceHDRContentToDefaultRefreshRate = false; }; } // namespace android diff --git a/services/surfaceflinger/Scheduler/StrongTyping.h b/services/surfaceflinger/Scheduler/StrongTyping.h index 02db022e08..e8ca0ba836 100644 --- a/services/surfaceflinger/Scheduler/StrongTyping.h +++ b/services/surfaceflinger/Scheduler/StrongTyping.h @@ -51,13 +51,22 @@ struct Compare : Ability<T, Compare> { inline bool operator>(T const& other) const { return !(*this < other || *this == other); } }; +template <typename T> +struct Hash : Ability<T, Hash> { + [[nodiscard]] std::size_t hash() const { + return std::hash<typename std::remove_const< + typename std::remove_reference<decltype(this->base().value())>::type>::type>{}( + this->base().value()); + } +}; + template <typename T, typename W, template <typename> class... Ability> struct StrongTyping : Ability<StrongTyping<T, W, Ability...>>... { StrongTyping() : mValue(0) {} explicit StrongTyping(T const& value) : mValue(value) {} StrongTyping(StrongTyping const&) = default; StrongTyping& operator=(StrongTyping const&) = default; - inline operator T() const { return mValue; } + explicit inline operator T() const { return mValue; } T const& value() const { return mValue; } T& value() { return mValue; } @@ -65,3 +74,12 @@ private: T mValue; }; } // namespace android + +namespace std { +template <typename T, typename W, template <typename> class... Ability> +struct hash<android::StrongTyping<T, W, Ability...>> { + std::size_t operator()(android::StrongTyping<T, W, Ability...> const& k) const { + return k.hash(); + } +}; +} // namespace std diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h index 4a4bef8b2e..e001080015 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatch.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h @@ -34,7 +34,7 @@ enum class CancelResult { Cancelled, TooLate, Error }; */ class VSyncDispatch { public: - using CallbackToken = StrongTyping<size_t, class CallbackTokenTag, Compare>; + using CallbackToken = StrongTyping<size_t, class CallbackTokenTag, Compare, Hash>; virtual ~VSyncDispatch(); diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h index f0580999c6..0e12e7f321 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h @@ -106,7 +106,8 @@ private: VSyncDispatchTimerQueue(VSyncDispatchTimerQueue const&) = delete; VSyncDispatchTimerQueue& operator=(VSyncDispatchTimerQueue const&) = delete; - using CallbackMap = std::unordered_map<size_t, std::shared_ptr<VSyncDispatchTimerQueueEntry>>; + using CallbackMap = + std::unordered_map<CallbackToken, std::shared_ptr<VSyncDispatchTimerQueueEntry>>; void timerCallback(); void setTimer(nsecs_t, nsecs_t) REQUIRES(mMutex); diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp index 27fd76cba3..8de35b1c2f 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp +++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp @@ -134,18 +134,13 @@ void VSyncModulator::updateOffsetsLocked() { return; } - const bool isDefault = mOffsets.fpsMode == RefreshRateType::DEFAULT; - const bool isPerformance = mOffsets.fpsMode == RefreshRateType::PERFORMANCE; const bool isEarly = &offsets == &mOffsetsConfig.early; const bool isEarlyGl = &offsets == &mOffsetsConfig.earlyGl; const bool isLate = &offsets == &mOffsetsConfig.late; - ATRACE_INT("Vsync-EarlyOffsetsOn", isDefault && isEarly); - ATRACE_INT("Vsync-EarlyGLOffsetsOn", isDefault && isEarlyGl); - ATRACE_INT("Vsync-LateOffsetsOn", isDefault && isLate); - ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn", isPerformance && isEarly); - ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn", isPerformance && isEarlyGl); - ATRACE_INT("Vsync-HighFpsLateOffsetsOn", isPerformance && isLate); + ATRACE_INT("Vsync-EarlyOffsetsOn", isEarly); + ATRACE_INT("Vsync-EarlyGLOffsetsOn", isEarlyGl); + ATRACE_INT("Vsync-LateOffsetsOn", isLate); } } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index 727cef26fe..63c0feb9cc 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -37,13 +37,10 @@ private: // switch in and out of gl composition. static constexpr int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2; - using RefreshRateType = RefreshRateConfigs::RefreshRateType; - public: // Wrapper for a collection of surfaceflinger/app offsets for a particular // configuration. struct Offsets { - RefreshRateType fpsMode; nsecs_t sf; nsecs_t app; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index bf3b4c9f01..5aa2447419 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -542,14 +542,8 @@ void SurfaceFlinger::bootFinished() if (mRefreshRateConfigs->refreshRateSwitchingSupported()) { // set the refresh rate according to the policy - const auto& performanceRefreshRate = - mRefreshRateConfigs->getRefreshRateFromType(RefreshRateType::PERFORMANCE); - - if (isDisplayConfigAllowed(performanceRefreshRate.configId)) { - setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None); - } else { - setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None); - } + const auto& performanceRefreshRate = mRefreshRateConfigs->getMaxRefreshRateByPolicy(); + changeRefreshRateLocked(performanceRefreshRate, Scheduler::ConfigEvent::None); } })); } @@ -821,9 +815,8 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& displayToken, info.xdpi = xdpi; info.ydpi = ydpi; info.fps = 1e9 / hwConfig->getVsyncPeriod(); - const auto refreshRateType = - mRefreshRateConfigs->getRefreshRateTypeFromHwcConfigId(hwConfig->getId()); - const auto offset = mPhaseOffsets->getOffsetsForRefreshRate(refreshRateType); + + const auto offset = mPhaseOffsets->getOffsetsForRefreshRate(info.fps); info.appVsyncOffset = offset.late.app; // This is how far in advance a buffer must be queued for @@ -873,17 +866,17 @@ int SurfaceFlinger::getActiveConfig(const sp<IBinder>& displayToken) { if (display->isPrimary()) { std::lock_guard<std::mutex> lock(mActiveConfigLock); if (mDesiredActiveConfigChanged) { - return mDesiredActiveConfig.configId; - } else { - return display->getActiveConfig(); + return mDesiredActiveConfig.configId.value(); } - } else { - return display->getActiveConfig(); } + + return display->getActiveConfig().value(); } void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { ATRACE_CALL(); + auto refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(info.configId); + ALOGV("setDesiredActiveConfig(%s)", refreshRate.name.c_str()); // Don't check against the current mode yet. Worst case we set the desired // config twice. However event generation config might have changed so we need to update it @@ -902,13 +895,14 @@ void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { // As we called to set period, we will call to onRefreshRateChangeCompleted once // DispSync model is locked. mVSyncModulator->onRefreshRateChangeInitiated(); - mPhaseOffsets->setRefreshRateType(info.type); + + mPhaseOffsets->setRefreshRateFps(refreshRate.fps); mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets()); } mDesiredActiveConfigChanged = true; if (mRefreshRateOverlay) { - mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type); + mRefreshRateOverlay->changeRefreshRate(refreshRate); } } @@ -930,14 +924,15 @@ void SurfaceFlinger::setActiveConfigInternal() { } std::lock_guard<std::mutex> lock(mActiveConfigLock); - mRefreshRateConfigs->setCurrentConfig(mUpcomingActiveConfig.configId); + mRefreshRateConfigs->setCurrentConfigId(mUpcomingActiveConfig.configId); mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId); - display->setActiveConfig(mUpcomingActiveConfig.configId); - mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type); + auto refreshRate = + mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId); + mPhaseOffsets->setRefreshRateFps(refreshRate.fps); mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets()); - ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId); + ATRACE_INT("ActiveConfigFPS", refreshRate.fps); if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) { mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, @@ -951,12 +946,15 @@ void SurfaceFlinger::desiredActiveConfigChangeDone() { mDesiredActiveConfigChanged = false; mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); - mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type); + auto refreshRate = + mRefreshRateConfigs->getRefreshRateFromConfigId(mDesiredActiveConfig.configId); + mPhaseOffsets->setRefreshRateFps(refreshRate.fps); mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets()); } bool SurfaceFlinger::performSetActiveConfig() { ATRACE_CALL(); + ALOGV("performSetActiveConfig"); if (mCheckPendingFence) { if (previousFrameMissed()) { // fence has not signaled yet. wait for the next invalidate @@ -980,6 +978,10 @@ bool SurfaceFlinger::performSetActiveConfig() { desiredActiveConfig = mDesiredActiveConfig; } + auto refreshRate = + mRefreshRateConfigs->getRefreshRateFromConfigId(desiredActiveConfig.configId); + ALOGV("performSetActiveConfig changing active config to %d(%s)", refreshRate.configId.value(), + refreshRate.name.c_str()); const auto display = getDefaultDisplayDeviceLocked(); if (!display || display->getActiveConfig() == desiredActiveConfig.configId) { // display is not valid or we are already in the requested mode @@ -1000,8 +1002,8 @@ bool SurfaceFlinger::performSetActiveConfig() { const auto displayId = display->getId(); LOG_ALWAYS_FATAL_IF(!displayId); - ATRACE_INT("ActiveConfigModeHWC", mUpcomingActiveConfig.configId); - getHwComposer().setActiveConfig(*displayId, mUpcomingActiveConfig.configId); + ATRACE_INT("ActiveConfigFPS_HWC", refreshRate.fps); + getHwComposer().setActiveConfig(*displayId, mUpcomingActiveConfig.configId.value()); // we need to submit an empty frame to HWC to start the process mCheckPendingFence = true; @@ -1396,11 +1398,12 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { *compositorTiming = getBE().mCompositorTiming; } -bool SurfaceFlinger::isDisplayConfigAllowed(int32_t configId) const { +bool SurfaceFlinger::isDisplayConfigAllowed(HwcConfigIndexType configId) const { return mAllowedDisplayConfigs.empty() || mAllowedDisplayConfigs.count(configId); } -void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::ConfigEvent event) { +void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate, + Scheduler::ConfigEvent event) { const auto display = getDefaultDisplayDeviceLocked(); if (!display || mBootStage != BootStage::FINISHED) { return; @@ -1408,15 +1411,13 @@ void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::Co ATRACE_CALL(); // Don't do any updating if the current fps is the same as the new one. - const auto& refreshRateConfig = mRefreshRateConfigs->getRefreshRateFromType(refreshRate); - const int desiredConfigId = refreshRateConfig.configId; - - if (!isDisplayConfigAllowed(desiredConfigId)) { - ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId); + if (!isDisplayConfigAllowed(refreshRate.configId)) { + ALOGV("Skipping config %d as it is not part of allowed configs", + refreshRate.configId.value()); return; } - setDesiredActiveConfig({refreshRate, desiredConfigId, event}); + setDesiredActiveConfig({refreshRate.configId, event}); } void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId, @@ -2180,7 +2181,8 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( Dataspace::UNKNOWN}); if (!state.isVirtual()) { LOG_ALWAYS_FATAL_IF(!displayId); - display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId)); + auto activeConfigId = HwcConfigIndexType(getHwComposer().getActiveConfigIndex(*displayId)); + display->setActiveConfig(activeConfigId); } display->setLayerStack(state.layerStack); @@ -2520,6 +2522,12 @@ void SurfaceFlinger::updateCursorAsync() mCompositionEngine->updateCursorAsync(refreshArgs); } +void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, + Scheduler::ConfigEvent event) { + Mutex::Autolock lock(mStateLock); + changeRefreshRateLocked(refreshRate, event); +} + void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) { if (mScheduler) { // In practice it's not allowed to hotplug in/out the primary display once it's been @@ -2528,7 +2536,7 @@ void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) { return; } - int currentConfig = getHwComposer().getActiveConfigIndex(primaryDisplayId); + auto currentConfig = HwcConfigIndexType(getHwComposer().getActiveConfigIndex(primaryDisplayId)); mRefreshRateConfigs = std::make_unique<scheduler::RefreshRateConfigs>(refresh_rate_switching(false), getHwComposer().getConfigs( @@ -2562,11 +2570,7 @@ void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) { new RegionSamplingThread(*this, *mScheduler, RegionSamplingThread::EnvironmentTimingTunables()); - mScheduler->setChangeRefreshRateCallback( - [this](RefreshRateType type, Scheduler::ConfigEvent event) { - Mutex::Autolock lock(mStateLock); - setRefreshRateTo(type, event); - }); + mScheduler->setSchedulerCallback(this); } void SurfaceFlinger::commitTransaction() @@ -3966,9 +3970,10 @@ void SurfaceFlinger::dumpVSync(std::string& result) const { dispSyncPresentTimeOffset, getVsyncPeriod()); StringAppendF(&result, "Allowed Display Configs: "); - for (int32_t configId : mAllowedDisplayConfigs) { + for (auto configId : mAllowedDisplayConfigs) { StringAppendF(&result, "%" PRIu32 " Hz, ", - mRefreshRateConfigs->getRefreshRateFromConfigId(configId).fps); + static_cast<int32_t>( + mRefreshRateConfigs->getRefreshRateFromConfigId(configId).fps)); } StringAppendF(&result, "(config override by backdoor: %s)\n\n", mDebugDisplayConfigSetByBackdoor ? "yes" : "no"); @@ -4809,13 +4814,9 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r n = data.readInt32(); if (n && !mRefreshRateOverlay && mRefreshRateConfigs->refreshRateSwitchingSupported()) { - RefreshRateType type; - { - std::lock_guard<std::mutex> lock(mActiveConfigLock); - type = mDesiredActiveConfig.type; - } mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this); - mRefreshRateOverlay->changeRefreshRate(type); + auto current = mRefreshRateConfigs->getCurrentRefreshRate(); + mRefreshRateOverlay->changeRefreshRate(current); } else if (!n) { mRefreshRateOverlay.reset(); } @@ -5417,28 +5418,48 @@ void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& d mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, display->getActiveConfig()); + // Prepare the parameters needed for RefreshRateConfigs::setPolicy. This will change to just + // passthrough once DisplayManager provide these parameters directly. + const auto refreshRate = + mRefreshRateConfigs->getRefreshRateFromConfigId(HwcConfigIndexType(allowedConfigs[0])); + const auto defaultModeId = refreshRate.configId; + auto minRefreshRateFps = refreshRate.fps; + auto maxRefreshRateFps = minRefreshRateFps; + + for (auto config : allowedConfigs) { + const auto configRefreshRate = + mRefreshRateConfigs->getRefreshRateFromConfigId(HwcConfigIndexType(config)); + if (configRefreshRate.fps < minRefreshRateFps) { + minRefreshRateFps = configRefreshRate.fps; + } else if (configRefreshRate.fps > maxRefreshRateFps) { + maxRefreshRateFps = configRefreshRate.fps; + } + } + mRefreshRateConfigs->setPolicy(defaultModeId, minRefreshRateFps, maxRefreshRateFps); + if (mRefreshRateConfigs->refreshRateSwitchingSupported()) { - const auto& type = mScheduler->getPreferredRefreshRateType(); - const auto& config = mRefreshRateConfigs->getRefreshRateFromType(type); - if (isDisplayConfigAllowed(config.configId)) { - ALOGV("switching to Scheduler preferred config %d", config.configId); - setDesiredActiveConfig({type, config.configId, Scheduler::ConfigEvent::Changed}); + auto configId = mScheduler->getPreferredConfigId(); + auto preferredRefreshRate = configId + ? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId) + : mRefreshRateConfigs->getMinRefreshRateByPolicy(); + ALOGV("trying to switch to Scheduler preferred config %d (%s)", + preferredRefreshRate.configId.value(), preferredRefreshRate.name.c_str()); + if (isDisplayConfigAllowed(preferredRefreshRate.configId)) { + ALOGV("switching to Scheduler preferred config %d", + preferredRefreshRate.configId.value()); + setDesiredActiveConfig( + {preferredRefreshRate.configId, Scheduler::ConfigEvent::Changed}); } else { - // Set the highest allowed config by iterating backwards on available refresh rates - const auto& refreshRates = mRefreshRateConfigs->getRefreshRateMap(); - for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) { - if (isDisplayConfigAllowed(iter->second.configId)) { - ALOGV("switching to allowed config %d", iter->second.configId); - setDesiredActiveConfig( - {iter->first, iter->second.configId, Scheduler::ConfigEvent::Changed}); - break; - } - } + // Set the highest allowed config + setDesiredActiveConfig({mRefreshRateConfigs->getMaxRefreshRateByPolicy().configId, + Scheduler::ConfigEvent::Changed}); + } + } else { + if (!allowedConfigs.empty()) { + ALOGV("switching to config %d", allowedConfigs[0]); + auto configId = HwcConfigIndexType(allowedConfigs[0]); + setDesiredActiveConfig({configId, Scheduler::ConfigEvent::Changed}); } - } else if (!allowedConfigs.empty()) { - ALOGV("switching to config %d", allowedConfigs[0]); - setDesiredActiveConfig( - {RefreshRateType::DEFAULT, allowedConfigs[0], Scheduler::ConfigEvent::Changed}); } } @@ -5487,7 +5508,10 @@ status_t SurfaceFlinger::getAllowedDisplayConfigs(const sp<IBinder>& displayToke } if (display->isPrimary()) { - outAllowedConfigs->assign(mAllowedDisplayConfigs.begin(), mAllowedDisplayConfigs.end()); + outAllowedConfigs->reserve(mAllowedDisplayConfigs.size()); + for (auto configId : mAllowedDisplayConfigs) { + outAllowedConfigs->push_back(configId.value()); + } } return NO_ERROR; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8e1199ca59..900c5f7f71 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -174,7 +174,8 @@ class SurfaceFlinger : public BnSurfaceComposer, public PriorityDumper, public ClientCache::ErasedRecipient, private IBinder::DeathRecipient, - private HWC2::ComposerCallback { + private HWC2::ComposerCallback, + private Scheduler::ISchedulerCallback { public: SurfaceFlingerBE& getBE() { return mBE; } const SurfaceFlingerBE& getBE() const { return mBE; } @@ -495,6 +496,10 @@ private: const hwc_vsync_period_change_timeline_t& updatedTimeline) override; /* ------------------------------------------------------------------------ + * Scheduler::ISchedulerCallback + */ + void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ConfigEvent) override; + /* ------------------------------------------------------------------------ * Message handling */ void waitForEvent(); @@ -504,15 +509,14 @@ private: void signalLayerUpdate(); void signalRefresh(); - using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; + using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; struct ActiveConfigInfo { - RefreshRateType type = RefreshRateType::DEFAULT; - int configId = 0; + HwcConfigIndexType configId; Scheduler::ConfigEvent event = Scheduler::ConfigEvent::None; bool operator!=(const ActiveConfigInfo& other) const { - return type != other.type || configId != other.configId || event != other.event; + return configId != other.configId || event != other.event; } }; @@ -787,9 +791,10 @@ private: // Sets the refresh rate by switching active configs, if they are available for // the desired refresh rate. - void setRefreshRateTo(RefreshRateType, Scheduler::ConfigEvent event) REQUIRES(mStateLock); + void changeRefreshRateLocked(const RefreshRate&, Scheduler::ConfigEvent event) + REQUIRES(mStateLock); - bool isDisplayConfigAllowed(int32_t configId) const REQUIRES(mStateLock); + bool isDisplayConfigAllowed(HwcConfigIndexType configId) const REQUIRES(mStateLock); bool previousFrameMissed(int graceTimeMs = 0); @@ -1113,7 +1118,7 @@ private: std::atomic<nsecs_t> mExpectedPresentTime = 0; // All configs are allowed if the set is empty. - using DisplayConfigs = std::set<int32_t>; + using DisplayConfigs = std::set<HwcConfigIndexType>; DisplayConfigs mAllowedDisplayConfigs GUARDED_BY(mStateLock); std::mutex mActiveConfigLock; diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index db7d04c8e3..76e8171255 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -1427,7 +1427,7 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { // Note: This is not Case::Display::HWC_ACTIVE_CONFIG_ID as the ids are // remapped, and the test only ever sets up one config. If there were an error // looking up the remapped index, device->getActiveConfig() would be -1 instead. - EXPECT_EQ(0, device->getActiveConfig()); + EXPECT_EQ(0, device->getActiveConfig().value()); EXPECT_EQ(Case::PerFrameMetadataSupport::PER_FRAME_METADATA_KEYS, device->getSupportedPerFrameMetadata()); } diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 2662f52581..80bca021ab 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -26,6 +26,7 @@ #include "AsyncCallRecorder.h" #include "Scheduler/EventThread.h" +#include "Scheduler/HwcStrongTypes.h" using namespace std::chrono_literals; using namespace std::placeholders; @@ -34,6 +35,7 @@ using testing::_; using testing::Invoke; namespace android { + namespace { constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID = 111; @@ -448,17 +450,17 @@ TEST_F(EventThreadTest, postHotplugExternalConnect) { } TEST_F(EventThreadTest, postConfigChangedPrimary) { - mThread->onConfigChanged(INTERNAL_DISPLAY_ID, 7); + mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(7)); expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7); } TEST_F(EventThreadTest, postConfigChangedExternal) { - mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, 5); + mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, HwcConfigIndexType(5)); expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5); } TEST_F(EventThreadTest, postConfigChangedPrimary64bit) { - mThread->onConfigChanged(DISPLAY_ID_64BIT, 7); + mThread->onConfigChanged(DISPLAY_ID_64BIT, HwcConfigIndexType(7)); expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7); } @@ -468,7 +470,7 @@ TEST_F(EventThreadTest, suppressConfigChanged) { createConnection(suppressConnectionEventRecorder, ISurfaceComposer::eConfigChangedSuppress); - mThread->onConfigChanged(INTERNAL_DISPLAY_ID, 9); + mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(9)); expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9); auto args = suppressConnectionEventRecorder.waitForCall(); diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h index 66c7f6b81f..da4eea0221 100644 --- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h +++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h @@ -25,16 +25,16 @@ namespace android::scheduler { struct FakePhaseOffsets : PhaseOffsets { static constexpr nsecs_t FAKE_PHASE_OFFSET_NS = 0; - Offsets getOffsetsForRefreshRate(RefreshRateType) const override { return getCurrentOffsets(); } + Offsets getOffsetsForRefreshRate(float) const override { return getCurrentOffsets(); } Offsets getCurrentOffsets() const override { - return {{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, - {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, - {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, + return {{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, + {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, + {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, FAKE_PHASE_OFFSET_NS}; } - void setRefreshRateType(RefreshRateType) override {} + void setRefreshRateFps(float) override {} void dump(std::string&) const override {} }; diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index e93d31e7f2..d95252b67f 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -44,9 +44,15 @@ protected: auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); } RefreshRateConfigs mConfigs{true, - {RefreshRateConfigs::InputConfig{0, LO_FPS_PERIOD}, - RefreshRateConfigs::InputConfig{1, HI_FPS_PERIOD}}, - 0}; + { + RefreshRateConfigs::InputConfig{HwcConfigIndexType(0), + HwcConfigGroupType(0), + LO_FPS_PERIOD}, + RefreshRateConfigs::InputConfig{HwcConfigIndexType(1), + HwcConfigGroupType(0), + HI_FPS_PERIOD}, + }, + HwcConfigIndexType(0)}; TestableScheduler* const mScheduler{new TestableScheduler(mConfigs)}; TestableSurfaceFlinger mFlinger; @@ -57,7 +63,6 @@ namespace { TEST_F(LayerHistoryTest, oneLayer) { const auto layer = createLayer(); - constexpr bool isHDR = false; EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_EQ(1, layerCount()); @@ -69,14 +74,14 @@ TEST_F(LayerHistoryTest, oneLayer) { // 0 FPS is returned if active layers have insufficient history. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) { - history().record(layer.get(), 0, isHDR, mTime); + history().record(layer.get(), 0, mTime); EXPECT_FLOAT_EQ(0, history().summarize(mTime).maxRefreshRate); EXPECT_EQ(1, activeLayerCount()); } // High FPS is returned once enough history has been recorded. for (int i = 0; i < 10; i++) { - history().record(layer.get(), 0, isHDR, mTime); + history().record(layer.get(), 0, mTime); EXPECT_FLOAT_EQ(HI_FPS, history().summarize(mTime).maxRefreshRate); EXPECT_EQ(1, activeLayerCount()); } @@ -84,29 +89,25 @@ TEST_F(LayerHistoryTest, oneLayer) { TEST_F(LayerHistoryTest, oneHDRLayer) { const auto layer = createLayer(); - constexpr bool isHDR = true; EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); - history().record(layer.get(), 0, isHDR, mTime); + history().record(layer.get(), 0, mTime); auto summary = history().summarize(mTime); EXPECT_FLOAT_EQ(0, summary.maxRefreshRate); - EXPECT_TRUE(summary.isHDR); EXPECT_EQ(1, activeLayerCount()); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false)); summary = history().summarize(mTime); EXPECT_FLOAT_EQ(0, summary.maxRefreshRate); - EXPECT_FALSE(summary.isHDR); EXPECT_EQ(0, activeLayerCount()); } TEST_F(LayerHistoryTest, explicitTimestamp) { const auto layer = createLayer(); - constexpr bool isHDR = false; EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_EQ(1, layerCount()); @@ -114,7 +115,7 @@ TEST_F(LayerHistoryTest, explicitTimestamp) { nsecs_t time = mTime; for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { - history().record(layer.get(), time, isHDR, time); + history().record(layer.get(), time, time); time += LO_FPS_PERIOD; } @@ -127,7 +128,6 @@ TEST_F(LayerHistoryTest, multipleLayers) { auto layer1 = createLayer(); auto layer2 = createLayer(); auto layer3 = createLayer(); - constexpr bool isHDR = false; EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true)); @@ -141,7 +141,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { // layer1 is active but infrequent. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { - history().record(layer1.get(), time, isHDR, time); + history().record(layer1.get(), time, time); time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); } @@ -151,12 +151,12 @@ TEST_F(LayerHistoryTest, multipleLayers) { // layer2 is frequent and has high refresh rate. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { - history().record(layer2.get(), time, isHDR, time); + history().record(layer2.get(), time, time); time += HI_FPS_PERIOD; } // layer1 is still active but infrequent. - history().record(layer1.get(), time, isHDR, time); + history().record(layer1.get(), time, time); EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time).maxRefreshRate); EXPECT_EQ(2, activeLayerCount()); @@ -165,7 +165,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { // layer1 is no longer active. // layer2 is frequent and has low refresh rate. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { - history().record(layer2.get(), time, isHDR, time); + history().record(layer2.get(), time, time); time += LO_FPS_PERIOD; } @@ -178,10 +178,10 @@ TEST_F(LayerHistoryTest, multipleLayers) { constexpr int RATIO = LO_FPS_PERIOD / HI_FPS_PERIOD; for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) { if (i % RATIO == 0) { - history().record(layer2.get(), time, isHDR, time); + history().record(layer2.get(), time, time); } - history().record(layer3.get(), time, isHDR, time); + history().record(layer3.get(), time, time); time += HI_FPS_PERIOD; } @@ -190,7 +190,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { EXPECT_EQ(2, frequentLayerCount(time)); // layer3 becomes recently active. - history().record(layer3.get(), time, isHDR, time); + history().record(layer3.get(), time, time); EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time).maxRefreshRate); EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(2, frequentLayerCount(time)); @@ -205,7 +205,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { // layer2 still has low refresh rate. // layer3 becomes inactive. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { - history().record(layer2.get(), time, isHDR, time); + history().record(layer2.get(), time, time); time += LO_FPS_PERIOD; } @@ -222,7 +222,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { // layer3 becomes active and has high refresh rate. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { - history().record(layer3.get(), time, isHDR, time); + history().record(layer3.get(), time, time); time += HI_FPS_PERIOD; } diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index f315a8a86c..546e65c1ea 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -30,27 +30,19 @@ using testing::_; namespace android { namespace scheduler { -using RefreshRateType = RefreshRateConfigs::RefreshRateType; using RefreshRate = RefreshRateConfigs::RefreshRate; class RefreshRateConfigsTest : public testing::Test { protected: - static constexpr int CONFIG_ID_60 = 0; - static constexpr hwc2_config_t HWC2_CONFIG_ID_60 = 0; - static constexpr int CONFIG_ID_90 = 1; - static constexpr hwc2_config_t HWC2_CONFIG_ID_90 = 1; + static inline const HwcConfigIndexType HWC_CONFIG_ID_60 = HwcConfigIndexType(0); + static inline const HwcConfigIndexType HWC_CONFIG_ID_90 = HwcConfigIndexType(1); + static inline const HwcConfigGroupType HWC_GROUP_ID_0 = HwcConfigGroupType(0); + static inline const HwcConfigGroupType HWC_GROUP_ID_1 = HwcConfigGroupType(1); static constexpr int64_t VSYNC_60 = 16666667; static constexpr int64_t VSYNC_90 = 11111111; RefreshRateConfigsTest(); ~RefreshRateConfigsTest(); - - void assertRatesEqual(const RefreshRate& left, const RefreshRate& right) { - ASSERT_EQ(left.configId, right.configId); - ASSERT_EQ(left.name, right.name); - ASSERT_EQ(left.fps, right.fps); - ASSERT_EQ(left.vsyncPeriod, right.vsyncPeriod); - } }; RefreshRateConfigsTest::RefreshRateConfigsTest() { @@ -69,40 +61,173 @@ namespace { /* ------------------------------------------------------------------------ * Test cases */ -TEST_F(RefreshRateConfigsTest, oneDeviceConfig_isRejected) { - std::vector<RefreshRateConfigs::InputConfig> configs{{HWC2_CONFIG_ID_60, VSYNC_60}}; +TEST_F(RefreshRateConfigsTest, oneDeviceConfig_SwitchingSupported) { + std::vector<RefreshRateConfigs::InputConfig> configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}}; auto refreshRateConfigs = std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs, - /*currentConfig=*/0); + /*currentConfigId=*/HWC_CONFIG_ID_60); + ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); +} + +TEST_F(RefreshRateConfigsTest, oneDeviceConfig_SwitchingNotSupported) { + std::vector<RefreshRateConfigs::InputConfig> configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}}; + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs, + /*currentConfigId=*/HWC_CONFIG_ID_60); ASSERT_FALSE(refreshRateConfigs->refreshRateSwitchingSupported()); } TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) { - std::vector<RefreshRateConfigs::InputConfig> configs{{HWC2_CONFIG_ID_60, VSYNC_60}, - {HWC2_CONFIG_ID_90, VSYNC_90}}; + std::vector<RefreshRateConfigs::InputConfig> configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; auto refreshRateConfigs = std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs, - /*currentConfig=*/0); + /*currentConfigId=*/HWC_CONFIG_ID_60); ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); - const auto& rates = refreshRateConfigs->getRefreshRateMap(); - ASSERT_EQ(2, rates.size()); - const auto& defaultRate = rates.find(RefreshRateType::DEFAULT); - const auto& performanceRate = rates.find(RefreshRateType::PERFORMANCE); - ASSERT_NE(rates.end(), defaultRate); - ASSERT_NE(rates.end(), performanceRate); - - RefreshRate expectedDefaultConfig = {CONFIG_ID_60, "60fps", 60, VSYNC_60, HWC2_CONFIG_ID_60}; - assertRatesEqual(expectedDefaultConfig, defaultRate->second); - RefreshRate expectedPerformanceConfig = {CONFIG_ID_90, "90fps", 90, VSYNC_90, - HWC2_CONFIG_ID_90}; - assertRatesEqual(expectedPerformanceConfig, performanceRate->second); - - assertRatesEqual(expectedDefaultConfig, - refreshRateConfigs->getRefreshRateFromType(RefreshRateType::DEFAULT)); - assertRatesEqual(expectedPerformanceConfig, - refreshRateConfigs->getRefreshRateFromType(RefreshRateType::PERFORMANCE)); + + const auto minRate = refreshRateConfigs->getMinRefreshRate(); + const auto performanceRate = refreshRateConfigs->getMaxRefreshRate(); + + RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60}; + ASSERT_EQ(expectedDefaultConfig, minRate); + RefreshRate expectedPerformanceConfig = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", + 90}; + ASSERT_EQ(expectedPerformanceConfig, performanceRate); + + const auto minRateByPolicy = refreshRateConfigs->getMinRefreshRateByPolicy(); + const auto performanceRateByPolicy = refreshRateConfigs->getMaxRefreshRateByPolicy(); + ASSERT_EQ(minRateByPolicy, minRate); + ASSERT_EQ(performanceRateByPolicy, performanceRate); } + +TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differentGroups) { + std::vector<RefreshRateConfigs::InputConfig> configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_1, VSYNC_90}}}; + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs, + /*currentConfigId=*/HWC_CONFIG_ID_60); + + ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + const auto minRate = refreshRateConfigs->getMinRefreshRateByPolicy(); + const auto performanceRate = refreshRateConfigs->getMaxRefreshRate(); + const auto minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy(); + const auto performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy(); + + RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60}; + ASSERT_EQ(expectedDefaultConfig, minRate); + ASSERT_EQ(expectedDefaultConfig, minRate60); + ASSERT_EQ(expectedDefaultConfig, performanceRate60); + + refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 60, 90); + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90); + + ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + const auto minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy(); + const auto performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy(); + + RefreshRate expectedPerformanceConfig = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_1, "90fps", + 90}; + ASSERT_EQ(expectedPerformanceConfig, performanceRate); + ASSERT_EQ(expectedPerformanceConfig, minRate90); + ASSERT_EQ(expectedPerformanceConfig, performanceRate90); +} + +TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_policyChange) { + std::vector<RefreshRateConfigs::InputConfig> configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs, + /*currentConfigId=*/HWC_CONFIG_ID_60); + ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + auto minRate = refreshRateConfigs->getMinRefreshRateByPolicy(); + auto performanceRate = refreshRateConfigs->getMaxRefreshRateByPolicy(); + + RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60}; + ASSERT_EQ(expectedDefaultConfig, minRate); + RefreshRate expectedPerformanceConfig = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", + 90}; + ASSERT_EQ(expectedPerformanceConfig, performanceRate); + + refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60); + ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + + auto minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy(); + auto performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy(); + ASSERT_EQ(expectedDefaultConfig, minRate60); + ASSERT_EQ(expectedDefaultConfig, performanceRate60); +} + +TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getCurrentRefreshRate) { + std::vector<RefreshRateConfigs::InputConfig> configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs, + /*currentConfigId=*/HWC_CONFIG_ID_60); + { + auto current = refreshRateConfigs->getCurrentRefreshRate(); + EXPECT_EQ(current.configId, HWC_CONFIG_ID_60); + } + + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90); + { + auto current = refreshRateConfigs->getCurrentRefreshRate(); + EXPECT_EQ(current.configId, HWC_CONFIG_ID_90); + } + + refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 90, 90); + { + auto current = refreshRateConfigs->getCurrentRefreshRate(); + EXPECT_EQ(current.configId, HWC_CONFIG_ID_90); + } +} + +TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { + std::vector<RefreshRateConfigs::InputConfig> configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; + auto refreshRateConfigs = + std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs, + /*currentConfigId=*/HWC_CONFIG_ID_60); + + ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + + RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60}; + RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90}; + + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(90.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(60.0f)); + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(45.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(30.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(24.0f)); + + refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(90.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(60.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(45.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(30.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(24.0f)); + + refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 90, 90); + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(90.0f)); + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(60.0f)); + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(45.0f)); + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(30.0f)); + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(24.0f)); + refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 0, 120); + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(90.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(60.0f)); + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(45.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(30.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(24.0f)); +} + } // namespace } // namespace scheduler } // namespace android diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp index cec0b32a6b..ef4699f628 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp @@ -33,8 +33,9 @@ namespace scheduler { class RefreshRateStatsTest : public testing::Test { protected: - static constexpr int CONFIG_ID_90 = 0; - static constexpr int CONFIG_ID_60 = 1; + static inline const auto CONFIG_ID_0 = HwcConfigIndexType(0); + static inline const auto CONFIG_ID_1 = HwcConfigIndexType(1); + static inline const auto CONFIG_GROUP_0 = HwcConfigGroupType(0); static constexpr int64_t VSYNC_90 = 11111111; static constexpr int64_t VSYNC_60 = 16666667; @@ -43,10 +44,10 @@ protected: void init(const std::vector<RefreshRateConfigs::InputConfig>& configs) { mRefreshRateConfigs = std::make_unique<RefreshRateConfigs>( - /*refreshRateSwitching=*/true, configs, /*currentConfig=*/0); + /*refreshRateSwitching=*/true, configs, /*currentConfig=*/CONFIG_ID_0); mRefreshRateStats = std::make_unique<RefreshRateStats>(*mRefreshRateConfigs, mTimeStats, - /*currentConfig=*/0, + /*currentConfigId=*/CONFIG_ID_0, /*currentPowerMode=*/HWC_POWER_MODE_OFF); } @@ -72,7 +73,7 @@ namespace { * Test cases */ TEST_F(RefreshRateStatsTest, oneConfigTest) { - init({{CONFIG_ID_90, VSYNC_90}}); + init({{{CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90}}}); EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); @@ -91,7 +92,7 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(0u, times.count("90fps")); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); + mRefreshRateStats->setConfigMode(CONFIG_ID_0); mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL); screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); @@ -107,7 +108,7 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); + mRefreshRateStats->setConfigMode(CONFIG_ID_0); screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); @@ -118,7 +119,7 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { } TEST_F(RefreshRateStatsTest, twoConfigsTest) { - init({{CONFIG_ID_90, VSYNC_90}, {CONFIG_ID_60, VSYNC_60}}); + init({{{CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90}, {CONFIG_ID_1, CONFIG_GROUP_0, VSYNC_60}}}); EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1)); @@ -137,7 +138,7 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); + mRefreshRateStats->setConfigMode(CONFIG_ID_0); mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL); screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); @@ -147,7 +148,7 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { EXPECT_LT(0, times["90fps"]); // When power mode is normal, time for configs updates. - mRefreshRateStats->setConfigMode(CONFIG_ID_60); + mRefreshRateStats->setConfigMode(CONFIG_ID_1); int ninety = mRefreshRateStats->getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); @@ -156,7 +157,7 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { ASSERT_EQ(1u, times.count("60fps")); EXPECT_LT(0, times["60fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); + mRefreshRateStats->setConfigMode(CONFIG_ID_0); int sixty = mRefreshRateStats->getTotalTimes()["60fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); @@ -164,7 +165,7 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { EXPECT_LT(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_60); + mRefreshRateStats->setConfigMode(CONFIG_ID_1); ninety = mRefreshRateStats->getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); @@ -175,7 +176,7 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config // does not update refresh rates that come from the config. mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); + mRefreshRateStats->setConfigMode(CONFIG_ID_0); sixty = mRefreshRateStats->getTotalTimes()["60fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); @@ -183,7 +184,7 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { EXPECT_EQ(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_60); + mRefreshRateStats->setConfigMode(CONFIG_ID_1); screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index b4cc1e15e8..40536abc5d 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -50,10 +50,11 @@ SchedulerTest::SchedulerTest() { ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{{/*hwcId=*/0, 16666667}}; - mRefreshRateConfigs = - std::make_unique<scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs, - /*currentConfig=*/0); + std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{ + {{HwcConfigIndexType(0), HwcConfigGroupType(0), 16666667}}}; + mRefreshRateConfigs = std::make_unique< + scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs, + /*currentConfig=*/HwcConfigIndexType(0)); mScheduler = std::make_unique<TestableScheduler>(*mRefreshRateConfigs); diff --git a/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp b/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp index b9ddcd77d0..54068797a1 100644 --- a/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp +++ b/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp @@ -56,18 +56,18 @@ TEST(StrongTypeTest, addition) { EXPECT_THAT(f1 + f2, Eq(FunkyType(32))); EXPECT_THAT(f2 + f1, Eq(FunkyType(32))); - EXPECT_THAT(++f1, Eq(11)); - EXPECT_THAT(f1, Eq(11)); - EXPECT_THAT(f1++, Eq(11)); - EXPECT_THAT(f1++, Eq(12)); - EXPECT_THAT(f1, Eq(13)); + EXPECT_THAT(++f1.value(), Eq(11)); + EXPECT_THAT(f1.value(), Eq(11)); + EXPECT_THAT(f1++.value(), Eq(11)); + EXPECT_THAT(f1++.value(), Eq(12)); + EXPECT_THAT(f1.value(), Eq(13)); auto f3 = f1; EXPECT_THAT(f1, Eq(f3)); EXPECT_THAT(f1, Lt(f2)); f3 += f1; - EXPECT_THAT(f1, Eq(13)); - EXPECT_THAT(f3, Eq(26)); + EXPECT_THAT(f1.value(), Eq(13)); + EXPECT_THAT(f3.value(), Eq(26)); } } // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 94fc5f7273..c4b8408202 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -193,15 +193,15 @@ public: std::unique_ptr<EventControlThread> eventControlThread, std::unique_ptr<EventThread> appEventThread, std::unique_ptr<EventThread> sfEventThread) { - std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{{/*hwcId=*/0, 16666667}}; - mFlinger->mRefreshRateConfigs = - std::make_unique<scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, - configs, /*currentConfig=*/0); - mFlinger->mRefreshRateStats = - std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mRefreshRateConfigs, - *mFlinger->mTimeStats, - /*currentConfig=*/0, - /*powerMode=*/HWC_POWER_MODE_OFF); + std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{ + {{HwcConfigIndexType(0), HwcConfigGroupType(0), 16666667}}}; + mFlinger->mRefreshRateConfigs = std::make_unique< + scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs, + /*currentConfig=*/HwcConfigIndexType(0)); + mFlinger->mRefreshRateStats = std::make_unique< + scheduler::RefreshRateStats>(*mFlinger->mRefreshRateConfigs, *mFlinger->mTimeStats, + /*currentConfig=*/HwcConfigIndexType(0), + /*powerMode=*/HWC_POWER_MODE_OFF); mScheduler = new TestableScheduler(std::move(primaryDispSync), std::move(eventControlThread), @@ -429,6 +429,7 @@ public: static constexpr int32_t DEFAULT_WIDTH = 1920; static constexpr int32_t DEFAULT_HEIGHT = 1280; static constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'666; + static constexpr int32_t DEFAULT_CONFIG_GROUP = 7; static constexpr int32_t DEFAULT_DPI = 320; static constexpr int32_t DEFAULT_ACTIVE_CONFIG = 0; static constexpr int32_t DEFAULT_POWER_MODE = 2; @@ -452,7 +453,7 @@ public: return *this; } - auto& setRefreshRate(int32_t refreshRate) { + auto& setRefreshRate(uint32_t refreshRate) { mRefreshRate = refreshRate; return *this; } @@ -499,6 +500,7 @@ public: config.setVsyncPeriod(mRefreshRate); config.setDpiX(mDpiX); config.setDpiY(mDpiY); + config.setConfigGroup(mConfigGroup); display->mutableConfigs().emplace(mActiveConfig, config.build()); display->mutableIsConnected() = true; display->setPowerMode(static_cast<HWC2::PowerMode>(mPowerMode)); @@ -522,8 +524,9 @@ public: hwc2_display_t mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID; int32_t mWidth = DEFAULT_WIDTH; int32_t mHeight = DEFAULT_HEIGHT; - int32_t mRefreshRate = DEFAULT_REFRESH_RATE; + uint32_t mRefreshRate = DEFAULT_REFRESH_RATE; int32_t mDpiX = DEFAULT_DPI; + int32_t mConfigGroup = DEFAULT_CONFIG_GROUP; int32_t mDpiY = DEFAULT_DPI; int32_t mActiveConfig = DEFAULT_ACTIVE_CONFIG; int32_t mPowerMode = DEFAULT_POWER_MODE; diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index ed35ebf2b6..f7c380490b 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -33,7 +33,7 @@ public: MOCK_METHOD0(onScreenReleased, void()); MOCK_METHOD0(onScreenAcquired, void()); MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool)); - MOCK_METHOD2(onConfigChanged, void(PhysicalDisplayId, int32_t)); + MOCK_METHOD2(onConfigChanged, void(PhysicalDisplayId, HwcConfigIndexType)); MOCK_CONST_METHOD1(dump, void(std::string&)); MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset)); MOCK_METHOD1(registerDisplayEventConnection, |