diff options
author | 2023-06-27 11:22:54 -0700 | |
---|---|---|
committer | 2023-08-22 13:52:42 -0700 | |
commit | ce6e0044cfea1e0ee38a48714364940a9de3e49a (patch) | |
tree | c956c0f654058748d68a5396a443108950407222 | |
parent | 652493db2c61804e81342bfd77f4b5e14dc02e1f (diff) |
Add setFrameRateCategory surface API
Bug: 284911776
Test: atest CtsSurfaceControlTestsStaging
Test: atest libsurfaceflinger_unittest
Change-Id: Ia804a63198ff096d1e5ffedf6046a0350963b8ed
22 files changed, 905 insertions, 219 deletions
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 2322b70d1c..e1afb524e7 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -83,6 +83,7 @@ layer_state_t::layer_state_t() frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), changeFrameRateStrategy(ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS), defaultFrameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), + frameRateCategory(ANATIVEWINDOW_FRAME_RATE_CATEGORY_DEFAULT), fixedTransformHint(ui::Transform::ROT_INVALID), autoRefresh(false), isTrustedOverlay(false), @@ -158,6 +159,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeByte, frameRateCompatibility); SAFE_PARCEL(output.writeByte, changeFrameRateStrategy); SAFE_PARCEL(output.writeByte, defaultFrameRateCompatibility); + SAFE_PARCEL(output.writeByte, frameRateCategory); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeBool, autoRefresh); SAFE_PARCEL(output.writeBool, dimmingEnabled); @@ -290,6 +292,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readByte, &frameRateCompatibility); SAFE_PARCEL(input.readByte, &changeFrameRateStrategy); SAFE_PARCEL(input.readByte, &defaultFrameRateCompatibility); + SAFE_PARCEL(input.readByte, &frameRateCategory); SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32); SAFE_PARCEL(input.readBool, &autoRefresh); @@ -659,6 +662,10 @@ void layer_state_t::merge(const layer_state_t& other) { frameRateCompatibility = other.frameRateCompatibility; changeFrameRateStrategy = other.changeFrameRateStrategy; } + if (other.what & eFrameRateCategoryChanged) { + what |= eFrameRateCategoryChanged; + frameRateCategory = other.frameRateCategory; + } if (other.what & eFixedTransformHintChanged) { what |= eFixedTransformHintChanged; fixedTransformHint = other.fixedTransformHint; @@ -769,6 +776,7 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const { CHECK_DIFF(diff, eFrameRateSelectionPriority, other, frameRateSelectionPriority); CHECK_DIFF3(diff, eFrameRateChanged, other, frameRate, frameRateCompatibility, changeFrameRateStrategy); + CHECK_DIFF(diff, eFrameRateCategoryChanged, other, frameRateCategory); CHECK_DIFF(diff, eFixedTransformHintChanged, other, fixedTransformHint); CHECK_DIFF(diff, eAutoRefreshChanged, other, autoRefresh); CHECK_DIFF(diff, eTrustedOverlayChanged, other, isTrustedOverlay); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 78401205ff..dc35c1c60e 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2092,6 +2092,18 @@ SurfaceComposerClient::Transaction::setDefaultFrameRateCompatibility(const sp<Su return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRateCategory( + const sp<SurfaceControl>& sc, int8_t category) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eFrameRateCategoryChanged; + s->frameRateCategory = category; + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixedTransformHint( const sp<SurfaceControl>& sc, int32_t fixedTransformHint) { layer_state_t* s = getLayerState(sc); diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 7aa7068538..03d52d27b5 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -181,7 +181,7 @@ struct layer_state_t { eRelativeLayerChanged = 0x00004000, eReparent = 0x00008000, eColorChanged = 0x00010000, - /* unused = 0x00020000, */ + eFrameRateCategoryChanged = 0x00020000, eBufferTransformChanged = 0x00040000, eTransformToDisplayInverseChanged = 0x00080000, eCropChanged = 0x00100000, @@ -213,7 +213,6 @@ struct layer_state_t { eTrustedOverlayChanged = 0x4000'00000000, eDropInputModeChanged = 0x8000'00000000, eExtendedRangeBrightnessChanged = 0x10000'00000000, - }; layer_state_t(); @@ -358,6 +357,9 @@ struct layer_state_t { // Default frame rate compatibility used to set the layer refresh rate votetype. int8_t defaultFrameRateCompatibility; + // Frame rate category to suggest what frame rate range a surface should run. + int8_t frameRateCategory; + // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that // the graphic producers should receive a transform hint as if the diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index dbcbd3bd62..fd9f186663 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -675,6 +675,8 @@ public: Transaction& setDefaultFrameRateCompatibility(const sp<SurfaceControl>& sc, int8_t compatibility); + Transaction& setFrameRateCategory(const sp<SurfaceControl>& sc, int8_t category); + // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that // the graphic producers should receive a transform hint as if the diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index edaa422e55..e158f01e8c 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1060,6 +1060,42 @@ enum { ANATIVEWINDOW_FRAME_RATE_MIN }; +/* + * Frame rate category values that can be used in Transaction::setFrameRateCategory. + */ +enum { + /** + * Default value. This value can also be set to return to default behavior, such as layers + * without animations. + */ + ANATIVEWINDOW_FRAME_RATE_CATEGORY_DEFAULT = 0, + + /** + * The layer will explicitly not influence the frame rate. + * This may indicate a frame rate suitable for no animation updates (such as a cursor blinking + * or a sporadic update). + */ + ANATIVEWINDOW_FRAME_RATE_CATEGORY_NO_PREFERENCE = 1, + + /** + * Indicates a frame rate suitable for animations that looks fine even if played at a low frame + * rate. + */ + ANATIVEWINDOW_FRAME_RATE_CATEGORY_LOW = 2, + + /** + * Indicates a middle frame rate suitable for animations that do not require higher frame + * rates, or do not benefit from high smoothness. This is normally 60 Hz or close to it. + */ + ANATIVEWINDOW_FRAME_RATE_CATEGORY_NORMAL = 3, + + /** + * Indicates a frame rate suitable for animations that require a high frame rate, which may + * increase smoothness but may also increase power usage. + */ + ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH = 4 +}; + static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) { return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate, diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 159d0f028d..758c46853d 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -675,8 +675,7 @@ void LayerSnapshotBuilder::updateFrameRateFromChildSnapshot(LayerSnapshot& snaps } using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility; - if (snapshot.frameRate.rate.isValid() || - snapshot.frameRate.type == FrameRateCompatibility::NoVote) { + if (snapshot.frameRate.isValid()) { // we already have a valid framerate. return; } @@ -684,15 +683,17 @@ void LayerSnapshotBuilder::updateFrameRateFromChildSnapshot(LayerSnapshot& snaps // We return whether this layer or its children has a vote. We ignore ExactOrMultiple votes // for the same reason we are allowing touch boost for those layers. See // RefreshRateSelector::rankFrameRates for details. - const auto layerVotedWithDefaultCompatibility = childSnapshot.frameRate.rate.isValid() && - childSnapshot.frameRate.type == FrameRateCompatibility::Default; + const auto layerVotedWithDefaultCompatibility = childSnapshot.frameRate.vote.rate.isValid() && + childSnapshot.frameRate.vote.type == FrameRateCompatibility::Default; const auto layerVotedWithNoVote = - childSnapshot.frameRate.type == FrameRateCompatibility::NoVote; - const auto layerVotedWithExactCompatibility = childSnapshot.frameRate.rate.isValid() && - childSnapshot.frameRate.type == FrameRateCompatibility::Exact; + childSnapshot.frameRate.vote.type == FrameRateCompatibility::NoVote; + const auto layerVotedWithCategory = + childSnapshot.frameRate.category != FrameRateCategory::Default; + const auto layerVotedWithExactCompatibility = childSnapshot.frameRate.vote.rate.isValid() && + childSnapshot.frameRate.vote.type == FrameRateCompatibility::Exact; bool childHasValidFrameRate = layerVotedWithDefaultCompatibility || layerVotedWithNoVote || - layerVotedWithExactCompatibility; + layerVotedWithCategory || layerVotedWithExactCompatibility; // If we don't have a valid frame rate, but the children do, we set this // layer as NoVote to allow the children to control the refresh rate @@ -820,11 +821,8 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a RequestedLayerState::Changes::Hierarchy) || snapshot.changes.any(RequestedLayerState::Changes::FrameRate | RequestedLayerState::Changes::Hierarchy)) { - snapshot.frameRate = (requested.requestedFrameRate.rate.isValid() || - (requested.requestedFrameRate.type == - scheduler::LayerInfo::FrameRateCompatibility::NoVote)) - ? requested.requestedFrameRate - : parentSnapshot.frameRate; + snapshot.frameRate = requested.requestedFrameRate.isValid() ? requested.requestedFrameRate + : parentSnapshot.frameRate; snapshot.changes |= RequestedLayerState::Changes::FrameRate; } diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index d979c4662e..43800e279f 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -24,6 +24,8 @@ #include <private/android_filesystem_config.h> #include <sys/types.h> +#include <scheduler/Fps.h> + #include "Layer.h" #include "LayerCreationArgs.h" #include "LayerLog.h" @@ -123,6 +125,7 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) dimmingEnabled = true; defaultFrameRateCompatibility = static_cast<int8_t>(scheduler::LayerInfo::FrameRateCompatibility::Default); + frameRateCategory = static_cast<int8_t>(FrameRateCategory::Default); dataspace = ui::Dataspace::V0_SRGB; gameMode = gui::GameMode::Unsupported; requestedFrameRate = {}; @@ -319,8 +322,14 @@ void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerSta Layer::FrameRate::convertCompatibility(clientState.frameRateCompatibility); const auto strategy = Layer::FrameRate::convertChangeFrameRateStrategy( clientState.changeFrameRateStrategy); - requestedFrameRate = - Layer::FrameRate(Fps::fromValue(clientState.frameRate), compatibility, strategy); + requestedFrameRate.vote = + Layer::FrameRate::FrameRateVote(Fps::fromValue(clientState.frameRate), + compatibility, strategy); + changes |= RequestedLayerState::Changes::FrameRate; + } + if (clientState.what & layer_state_t::eFrameRateCategoryChanged) { + const auto category = Layer::FrameRate::convertCategory(clientState.frameRateCategory); + requestedFrameRate.category = category; changes |= RequestedLayerState::Changes::FrameRate; } } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 59a8825de5..95e1a2f0d3 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -27,7 +27,6 @@ #include <android-base/properties.h> #include <android-base/stringprintf.h> -#include <android/native_window.h> #include <binder/IPCThreadState.h> #include <compositionengine/CompositionEngine.h> #include <compositionengine/Display.h> @@ -101,7 +100,7 @@ TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility; using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness; const auto frameRateCompatibility = [frameRate] { - switch (frameRate.type) { + switch (frameRate.vote.type) { case Layer::FrameRateCompatibility::Default: return FrameRateCompatibility::Default; case Layer::FrameRateCompatibility::ExactOrMultiple: @@ -112,7 +111,7 @@ TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate }(); const auto seamlessness = [frameRate] { - switch (frameRate.seamlessness) { + switch (frameRate.vote.seamlessness) { case scheduler::Seamlessness::OnlySeamless: return Seamlessness::ShouldBeSeamless; case scheduler::Seamlessness::SeamedAndSeamless: @@ -122,7 +121,7 @@ TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate } }(); - return TimeStats::SetFrameRateVote{.frameRate = frameRate.rate.getValue(), + return TimeStats::SetFrameRateVote{.frameRate = frameRate.vote.rate.getValue(), .frameRateCompatibility = frameRateCompatibility, .seamlessness = seamlessness}; } @@ -1264,8 +1263,7 @@ const half4& Layer::getBorderColor() { bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* transactionNeeded) { // The frame rate for layer tree is this layer's frame rate if present, or the parent frame rate const auto frameRate = [&] { - if (mDrawingState.frameRate.rate.isValid() || - mDrawingState.frameRate.type == FrameRateCompatibility::NoVote) { + if (mDrawingState.frameRate.isValid()) { return mDrawingState.frameRate; } @@ -1281,23 +1279,23 @@ bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* tran child->propagateFrameRateForLayerTree(frameRate, transactionNeeded); } - // If we don't have a valid frame rate, but the children do, we set this + // If we don't have a valid frame rate specification, but the children do, we set this // layer as NoVote to allow the children to control the refresh rate - if (!frameRate.rate.isValid() && frameRate.type != FrameRateCompatibility::NoVote && - childrenHaveFrameRate) { + if (!frameRate.isValid() && childrenHaveFrameRate) { *transactionNeeded |= setFrameRateForLayerTreeLegacy(FrameRate(Fps(), FrameRateCompatibility::NoVote)); } - // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes for + // We return whether this layer or its children has a vote. We ignore ExactOrMultiple votes for // the same reason we are allowing touch boost for those layers. See // RefreshRateSelector::rankFrameRates for details. const auto layerVotedWithDefaultCompatibility = - frameRate.rate.isValid() && frameRate.type == FrameRateCompatibility::Default; - const auto layerVotedWithNoVote = frameRate.type == FrameRateCompatibility::NoVote; + frameRate.vote.rate.isValid() && frameRate.vote.type == FrameRateCompatibility::Default; + const auto layerVotedWithNoVote = frameRate.vote.type == FrameRateCompatibility::NoVote; + const auto layerVotedWithCategory = frameRate.category != FrameRateCategory::Default; const auto layerVotedWithExactCompatibility = - frameRate.rate.isValid() && frameRate.type == FrameRateCompatibility::Exact; - return layerVotedWithDefaultCompatibility || layerVotedWithNoVote || + frameRate.vote.rate.isValid() && frameRate.vote.type == FrameRateCompatibility::Exact; + return layerVotedWithDefaultCompatibility || layerVotedWithNoVote || layerVotedWithCategory || layerVotedWithExactCompatibility || childrenHaveFrameRate; } @@ -1319,13 +1317,28 @@ void Layer::updateTreeHasFrameRateVote() { } } -bool Layer::setFrameRate(FrameRate frameRate) { - if (mDrawingState.frameRate == frameRate) { +bool Layer::setFrameRate(FrameRate::FrameRateVote frameRateVote) { + if (mDrawingState.frameRate.vote == frameRateVote) { return false; } mDrawingState.sequence++; - mDrawingState.frameRate = frameRate; + mDrawingState.frameRate.vote = frameRateVote; + mDrawingState.modified = true; + + updateTreeHasFrameRateVote(); + + setTransactionFlags(eTransactionNeeded); + return true; +} + +bool Layer::setFrameRateCategory(FrameRateCategory category) { + if (mDrawingState.frameRate.category == category) { + return false; + } + + mDrawingState.sequence++; + mDrawingState.frameRate.category = category; mDrawingState.modified = true; updateTreeHasFrameRateVote(); @@ -1651,10 +1664,10 @@ void Layer::miniDumpLegacy(std::string& result, const DisplayDevice& display) co StringAppendF(&result, "%6.1f %6.1f %6.1f %6.1f | ", crop.left, crop.top, crop.right, crop.bottom); const auto frameRate = getFrameRateForLayerTree(); - if (frameRate.rate.isValid() || frameRate.type != FrameRateCompatibility::Default) { - StringAppendF(&result, "%s %15s %17s", to_string(frameRate.rate).c_str(), - ftl::enum_string(frameRate.type).c_str(), - ftl::enum_string(frameRate.seamlessness).c_str()); + if (frameRate.vote.rate.isValid() || frameRate.vote.type != FrameRateCompatibility::Default) { + StringAppendF(&result, "%s %15s %17s", to_string(frameRate.vote.rate).c_str(), + ftl::enum_string(frameRate.vote.type).c_str(), + ftl::enum_string(frameRate.vote.seamlessness).c_str()); } else { result.append(41, ' '); } @@ -1686,10 +1699,10 @@ void Layer::miniDump(std::string& result, const frontend::LayerSnapshot& snapsho StringAppendF(&result, "%6.1f %6.1f %6.1f %6.1f | ", crop.left, crop.top, crop.right, crop.bottom); const auto frameRate = snapshot.frameRate; - if (frameRate.rate.isValid() || frameRate.type != FrameRateCompatibility::Default) { - StringAppendF(&result, "%s %15s %17s", to_string(frameRate.rate).c_str(), - ftl::enum_string(frameRate.type).c_str(), - ftl::enum_string(frameRate.seamlessness).c_str()); + if (frameRate.vote.rate.isValid() || frameRate.vote.type != FrameRateCompatibility::Default) { + StringAppendF(&result, "%s %15s %17s", to_string(frameRate.vote.rate).c_str(), + ftl::enum_string(frameRate.vote.type).c_str(), + ftl::enum_string(frameRate.vote.seamlessness).c_str()); } else { result.append(41, ' '); } @@ -2823,36 +2836,6 @@ void Layer::addChildToDrawing(const sp<Layer>& layer) { layer->mDrawingParent = sp<Layer>::fromExisting(this); } -Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t compatibility) { - switch (compatibility) { - case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT: - return FrameRateCompatibility::Default; - case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE: - return FrameRateCompatibility::ExactOrMultiple; - case ANATIVEWINDOW_FRAME_RATE_EXACT: - return FrameRateCompatibility::Exact; - case ANATIVEWINDOW_FRAME_RATE_MIN: - return FrameRateCompatibility::Min; - case ANATIVEWINDOW_FRAME_RATE_NO_VOTE: - return FrameRateCompatibility::NoVote; - default: - LOG_ALWAYS_FATAL("Invalid frame rate compatibility value %d", compatibility); - return FrameRateCompatibility::Default; - } -} - -scheduler::Seamlessness Layer::FrameRate::convertChangeFrameRateStrategy(int8_t strategy) { - switch (strategy) { - case ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS: - return Seamlessness::OnlySeamless; - case ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS: - return Seamlessness::SeamedAndSeamless; - default: - LOG_ALWAYS_FATAL("Invalid change frame sate strategy value %d", strategy); - return Seamlessness::Default; - } -} - bool Layer::isInternalDisplayOverlay() const { const State& s(mDrawingState); if (s.flags & layer_state_t::eLayerSkipScreenshot) { @@ -4366,13 +4349,6 @@ void Layer::updateLastLatchTime(nsecs_t latchTime) { mLastLatchTime = latchTime; } -// --------------------------------------------------------------------------- - -std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { - return stream << "{rate=" << rate.rate << " type=" << ftl::enum_string(rate.type) - << " seamlessness=" << ftl::enum_string(rate.seamlessness) << '}'; -} - } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index d1912e4c9c..568e4c49dd 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -778,7 +778,8 @@ public: */ Rect getCroppedBufferSize(const Layer::State& s) const; - bool setFrameRate(FrameRate); + bool setFrameRate(FrameRate::FrameRateVote); + bool setFrameRateCategory(FrameRateCategory); virtual void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {} void setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info, nsecs_t postTime); diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 5d00a26031..565a490ec8 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -40,8 +40,9 @@ namespace android::scheduler { namespace { bool isLayerActive(const LayerInfo& info, nsecs_t threshold) { - // Layers with an explicit vote are always kept active - if (info.getSetFrameRateVote().rate.isValid()) { + // Layers with an explicit frame rate or frame rate category are always kept active, + // but ignore NoVote/NoPreference. + if (info.getSetFrameRateVote().isValid() && !info.getSetFrameRateVote().isNoVote()) { return true; } @@ -70,6 +71,7 @@ void trace(const LayerInfo& info, LayerHistory::LayerVoteType type, int fps) { traceType(LayerHistory::LayerVoteType::ExplicitExact, fps); traceType(LayerHistory::LayerVoteType::Min, 1); traceType(LayerHistory::LayerVoteType::Max, 1); + traceType(LayerHistory::LayerVoteType::ExplicitCategory, 1); ALOGD("%s: %s @ %d Hz", __FUNCTION__, info.getName().c_str(), fps); } @@ -171,27 +173,32 @@ auto LayerHistory::summarize(const RefreshRateSelector& selector, nsecs_t now) - layerFocused ? "" : "not"); ATRACE_FORMAT("%s", info->getName().c_str()); - const auto vote = info->getRefreshRateVote(selector, now); - // Skip NoVote layer as those don't have any requirements - if (vote.type == LayerVoteType::NoVote) { - continue; - } + const auto votes = info->getRefreshRateVote(selector, now); + for (LayerInfo::LayerVote vote : votes) { + if (vote.isNoVote()) { + continue; + } + + // Compute the layer's position on the screen + const Rect bounds = Rect(info->getBounds()); + const ui::Transform transform = info->getTransform(); + constexpr bool roundOutwards = true; + Rect transformed = transform.transform(bounds, roundOutwards); + + const float layerArea = transformed.getWidth() * transformed.getHeight(); + float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f; + const std::string categoryString = vote.category == FrameRateCategory::Default + ? base::StringPrintf("category=%s", ftl::enum_string(vote.category).c_str()) + : ""; + ATRACE_FORMAT_INSTANT("%s %s %s (%d%)", ftl::enum_string(vote.type).c_str(), + to_string(vote.fps).c_str(), categoryString.c_str(), + weight * 100); + summary.push_back({info->getName(), info->getOwnerUid(), vote.type, vote.fps, + vote.seamlessness, vote.category, weight, layerFocused}); - // Compute the layer's position on the screen - const Rect bounds = Rect(info->getBounds()); - const ui::Transform transform = info->getTransform(); - constexpr bool roundOutwards = true; - Rect transformed = transform.transform(bounds, roundOutwards); - - const float layerArea = transformed.getWidth() * transformed.getHeight(); - float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f; - ATRACE_FORMAT_INSTANT("%s %s (%d%)", ftl::enum_string(vote.type).c_str(), - to_string(vote.fps).c_str(), weight * 100); - summary.push_back({info->getName(), info->getOwnerUid(), vote.type, vote.fps, - vote.seamlessness, weight, layerFocused}); - - if (CC_UNLIKELY(mTraceEnabled)) { - trace(*info, vote.type, vote.fps.getIntValue()); + if (CC_UNLIKELY(mTraceEnabled)) { + trace(*info, vote.type, vote.fps.getIntValue()); + } } } @@ -228,7 +235,7 @@ void LayerHistory::partitionLayers(nsecs_t now) { // Set layer vote if set const auto frameRate = info->getSetFrameRateVote(); const auto voteType = [&]() { - switch (frameRate.type) { + switch (frameRate.vote.type) { case Layer::FrameRateCompatibility::Default: return LayerVoteType::ExplicitDefault; case Layer::FrameRateCompatibility::Min: @@ -242,9 +249,10 @@ void LayerHistory::partitionLayers(nsecs_t now) { } }(); - if (frameRate.rate.isValid() || voteType == LayerVoteType::NoVote) { + if (frameRate.isValid()) { const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote; - info->setLayerVote({type, frameRate.rate, frameRate.seamlessness}); + info->setLayerVote({type, frameRate.vote.rate, frameRate.vote.seamlessness, + frameRate.category}); } else { info->resetLayerVote(); } diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index bae3739501..750803b2f9 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -26,10 +26,12 @@ #include <algorithm> #include <utility> +#include <android/native_window.h> #include <cutils/compiler.h> #include <cutils/trace.h> #include <ftl/enum.h> #include <gui/TraceUtils.h> +#include <system/window.h> #undef LOG_TAG #define LOG_TAG "LayerInfo" @@ -265,19 +267,34 @@ std::optional<Fps> LayerInfo::calculateRefreshRateIfPossible(const RefreshRateSe : std::nullopt; } -LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateSelector& selector, - nsecs_t now) { +LayerInfo::RefreshRateVotes LayerInfo::getRefreshRateVote(const RefreshRateSelector& selector, + nsecs_t now) { ATRACE_CALL(); + LayerInfo::RefreshRateVotes votes; + if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) { - ALOGV("%s voted %d ", mName.c_str(), static_cast<int>(mLayerVote.type)); - return mLayerVote; + if (mLayerVote.category != FrameRateCategory::Default) { + ALOGV("%s uses frame rate category: %d", mName.c_str(), + static_cast<int>(mLayerVote.category)); + votes.push_back({LayerHistory::LayerVoteType::ExplicitCategory, mLayerVote.fps, + Seamlessness::Default, mLayerVote.category}); + } + + if (mLayerVote.fps.isValid() || + mLayerVote.type != LayerHistory::LayerVoteType::ExplicitDefault) { + ALOGV("%s voted %d ", mName.c_str(), static_cast<int>(mLayerVote.type)); + votes.push_back(mLayerVote); + } + + return votes; } if (isAnimating(now)) { ATRACE_FORMAT_INSTANT("animating"); ALOGV("%s is animating", mName.c_str()); mLastRefreshRate.animating = true; - return {LayerHistory::LayerVoteType::Max, Fps()}; + votes.push_back({LayerHistory::LayerVoteType::Max, Fps()}); + return votes; } const LayerInfo::Frequent frequent = isFrequent(now); @@ -288,7 +305,8 @@ LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateSelector& se mLastRefreshRate.infrequent = true; // Infrequent layers vote for minimal refresh rate for // battery saving purposes and also to prevent b/135718869. - return {LayerHistory::LayerVoteType::Min, Fps()}; + votes.push_back({LayerHistory::LayerVoteType::Min, Fps()}); + return votes; } if (frequent.clearHistory) { @@ -298,11 +316,13 @@ LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateSelector& se auto refreshRate = calculateRefreshRateIfPossible(selector, now); if (refreshRate.has_value()) { ALOGV("%s calculated refresh rate: %s", mName.c_str(), to_string(*refreshRate).c_str()); - return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()}; + votes.push_back({LayerHistory::LayerVoteType::Heuristic, refreshRate.value()}); + return votes; } ALOGV("%s Max (can't resolve refresh rate)", mName.c_str()); - return {LayerHistory::LayerVoteType::Max, Fps()}; + votes.push_back({LayerHistory::LayerVoteType::Max, Fps()}); + return votes; } const char* LayerInfo::getTraceTag(LayerHistory::LayerVoteType type) const { @@ -391,6 +411,68 @@ bool LayerInfo::RefreshRateHistory::isConsistent() const { return consistent; } +LayerInfo::FrameRateCompatibility LayerInfo::FrameRate::convertCompatibility(int8_t compatibility) { + switch (compatibility) { + case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT: + return FrameRateCompatibility::Default; + case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE: + return FrameRateCompatibility::ExactOrMultiple; + case ANATIVEWINDOW_FRAME_RATE_EXACT: + return FrameRateCompatibility::Exact; + case ANATIVEWINDOW_FRAME_RATE_MIN: + return FrameRateCompatibility::Min; + case ANATIVEWINDOW_FRAME_RATE_NO_VOTE: + return FrameRateCompatibility::NoVote; + default: + LOG_ALWAYS_FATAL("Invalid frame rate compatibility value %d", compatibility); + return FrameRateCompatibility::Default; + } +} + +Seamlessness LayerInfo::FrameRate::convertChangeFrameRateStrategy(int8_t strategy) { + switch (strategy) { + case ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS: + return Seamlessness::OnlySeamless; + case ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS: + return Seamlessness::SeamedAndSeamless; + default: + LOG_ALWAYS_FATAL("Invalid change frame sate strategy value %d", strategy); + return Seamlessness::Default; + } +} + +FrameRateCategory LayerInfo::FrameRate::convertCategory(int8_t category) { + switch (category) { + case ANATIVEWINDOW_FRAME_RATE_CATEGORY_DEFAULT: + return FrameRateCategory::Default; + case ANATIVEWINDOW_FRAME_RATE_CATEGORY_NO_PREFERENCE: + return FrameRateCategory::NoPreference; + case ANATIVEWINDOW_FRAME_RATE_CATEGORY_LOW: + return FrameRateCategory::Low; + case ANATIVEWINDOW_FRAME_RATE_CATEGORY_NORMAL: + return FrameRateCategory::Normal; + case ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH: + return FrameRateCategory::High; + default: + LOG_ALWAYS_FATAL("Invalid frame rate category value %d", category); + return FrameRateCategory::Default; + } +} + +bool LayerInfo::FrameRate::isNoVote() const { + return vote.type == FrameRateCompatibility::NoVote || + category == FrameRateCategory::NoPreference; +} + +bool LayerInfo::FrameRate::isValid() const { + return isNoVote() || vote.rate.isValid() || category != FrameRateCategory::Default; +} + +std::ostream& operator<<(std::ostream& stream, const LayerInfo::FrameRate& rate) { + return stream << "{rate=" << rate.vote.rate << " type=" << ftl::enum_string(rate.vote.type) + << " seamlessness=" << ftl::enum_string(rate.vote.seamlessness) << '}'; +} + } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index c5a60573f5..7d2444c94b 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -25,6 +25,7 @@ #include <ui/Transform.h> #include <utils/Timers.h> +#include <scheduler/Fps.h> #include <scheduler/Seamlessness.h> #include "LayerHistory.h" @@ -67,8 +68,15 @@ public: LayerHistory::LayerVoteType type = LayerHistory::LayerVoteType::Heuristic; Fps fps; Seamlessness seamlessness = Seamlessness::Default; + // Category is in effect if fps is not specified. + FrameRateCategory category = FrameRateCategory::Default; + + // Returns true if the layer explicitly should contribute to frame rate scoring. + bool isNoVote() const { return RefreshRateSelector::isNoVote(type, category); } }; + using RefreshRateVotes = ftl::SmallVector<LayerInfo::LayerVote, 2>; + // FrameRateCompatibility specifies how we should interpret the frame rate associated with // the layer. enum class FrameRateCompatibility { @@ -87,24 +95,40 @@ public: ftl_last = NoVote }; - // Encapsulates the frame rate and compatibility of the layer. This information will be used + // Encapsulates the frame rate specifications of the layer. This information will be used // when the display refresh rate is determined. struct FrameRate { using Seamlessness = scheduler::Seamlessness; - Fps rate; - FrameRateCompatibility type = FrameRateCompatibility::Default; - Seamlessness seamlessness = Seamlessness::Default; + // Information related to a specific desired frame rate vote. + struct FrameRateVote { + Fps rate; + FrameRateCompatibility type = FrameRateCompatibility::Default; + Seamlessness seamlessness = Seamlessness::Default; + + bool operator==(const FrameRateVote& other) const { + return isApproxEqual(rate, other.rate) && type == other.type && + seamlessness == other.seamlessness; + } + + FrameRateVote() = default; + + FrameRateVote(Fps rate, FrameRateCompatibility type, + Seamlessness seamlessness = Seamlessness::OnlySeamless) + : rate(rate), type(type), seamlessness(getSeamlessness(rate, seamlessness)) {} + } vote; + + FrameRateCategory category = FrameRateCategory::Default; FrameRate() = default; FrameRate(Fps rate, FrameRateCompatibility type, - Seamlessness seamlessness = Seamlessness::OnlySeamless) - : rate(rate), type(type), seamlessness(getSeamlessness(rate, seamlessness)) {} + Seamlessness seamlessness = Seamlessness::OnlySeamless, + FrameRateCategory category = FrameRateCategory::Default) + : vote(FrameRateVote(rate, type, seamlessness)), category(category) {} bool operator==(const FrameRate& other) const { - return isApproxEqual(rate, other.rate) && type == other.type && - seamlessness == other.seamlessness; + return vote == other.vote && category == other.category; } bool operator!=(const FrameRate& other) const { return !(*this == other); } @@ -112,8 +136,22 @@ public: // Convert an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value to a // Layer::FrameRateCompatibility. Logs fatal if the compatibility value is invalid. static FrameRateCompatibility convertCompatibility(int8_t compatibility); + + // Convert an ANATIVEWINDOW_CHANGE_FRAME_RATE_* value to a scheduler::Seamlessness. + // Logs fatal if the compatibility value is invalid. static scheduler::Seamlessness convertChangeFrameRateStrategy(int8_t strategy); + // Convert an ANATIVEWINDOW_FRAME_RATE_CATEGORY_* value to a FrameRateCategory. + // Logs fatal if the compatibility value is invalid. + static FrameRateCategory convertCategory(int8_t category); + + // True if the FrameRate has explicit frame rate specifications. + bool isValid() const; + + // Returns true if the FrameRate explicitly instructs to not contribute to frame rate + // selection. + bool isNoVote() const; + private: static Seamlessness getSeamlessness(Fps rate, Seamlessness seamlessness) { if (!rate.isValid()) { @@ -148,13 +186,15 @@ public: void setDefaultLayerVote(LayerHistory::LayerVoteType type) { mDefaultVote = type; } // Resets the layer vote to its default. - void resetLayerVote() { mLayerVote = {mDefaultVote, Fps(), Seamlessness::Default}; } + void resetLayerVote() { + mLayerVote = {mDefaultVote, Fps(), Seamlessness::Default, FrameRateCategory::Default}; + } std::string getName() const { return mName; } uid_t getOwnerUid() const { return mOwnerUid; } - LayerVote getRefreshRateVote(const RefreshRateSelector&, nsecs_t now); + RefreshRateVotes getRefreshRateVote(const RefreshRateSelector&, nsecs_t now); // Return the last updated time. If the present time is farther in the future than the // updated time, the updated time is the present time. diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index fb985f7c5b..a7ba731323 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -275,6 +275,25 @@ std::pair<nsecs_t, nsecs_t> RefreshRateSelector::getDisplayFrames(nsecs_t layerP return {quotient, remainder}; } +float RefreshRateSelector::calculateNonExactMatchingDefaultLayerScoreLocked( + nsecs_t displayPeriod, nsecs_t layerPeriod) const { + // Find the actual rate the layer will render, assuming + // that layerPeriod is the minimal period to render a frame. + // For example if layerPeriod is 20ms and displayPeriod is 16ms, + // then the actualLayerPeriod will be 32ms, because it is the + // smallest multiple of the display period which is >= layerPeriod. + auto actualLayerPeriod = displayPeriod; + int multiplier = 1; + while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) { + multiplier++; + actualLayerPeriod = displayPeriod * multiplier; + } + + // Because of the threshold we used above it's possible that score is slightly + // above 1. + return std::min(1.0f, static_cast<float>(layerPeriod) / static_cast<float>(actualLayerPeriod)); +} + float RefreshRateSelector::calculateNonExactMatchingLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate) const { constexpr float kScoreForFractionalPairs = .8f; @@ -282,22 +301,7 @@ float RefreshRateSelector::calculateNonExactMatchingLayerScoreLocked(const Layer const auto displayPeriod = refreshRate.getPeriodNsecs(); const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs(); if (layer.vote == LayerVoteType::ExplicitDefault) { - // Find the actual rate the layer will render, assuming - // that layerPeriod is the minimal period to render a frame. - // For example if layerPeriod is 20ms and displayPeriod is 16ms, - // then the actualLayerPeriod will be 32ms, because it is the - // smallest multiple of the display period which is >= layerPeriod. - auto actualLayerPeriod = displayPeriod; - int multiplier = 1; - while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) { - multiplier++; - actualLayerPeriod = displayPeriod * multiplier; - } - - // Because of the threshold we used above it's possible that score is slightly - // above 1. - return std::min(1.0f, - static_cast<float>(layerPeriod) / static_cast<float>(actualLayerPeriod)); + return calculateNonExactMatchingDefaultLayerScoreLocked(displayPeriod, layerPeriod); } if (layer.vote == LayerVoteType::ExplicitExactOrMultiple || @@ -372,6 +376,22 @@ float RefreshRateSelector::calculateLayerScoreLocked(const LayerRequirement& lay constexpr float kSeamedSwitchPenalty = 0.95f; const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty; + if (layer.vote == LayerVoteType::ExplicitCategory) { + if (getFrameRateCategoryRange(layer.frameRateCategory).includes(refreshRate)) { + return 1.f; + } + + FpsRange categoryRange = getFrameRateCategoryRange(layer.frameRateCategory); + using fps_approx_ops::operator<; + if (refreshRate < categoryRange.min) { + return calculateNonExactMatchingDefaultLayerScoreLocked(refreshRate.getPeriodNsecs(), + categoryRange.min + .getPeriodNsecs()); + } + return calculateNonExactMatchingDefaultLayerScoreLocked(refreshRate.getPeriodNsecs(), + categoryRange.max.getPeriodNsecs()); + } + // If the layer wants Max, give higher score to the higher refresh rate if (layer.vote == LayerVoteType::Max) { return calculateDistanceScoreFromMax(refreshRate); @@ -391,7 +411,8 @@ float RefreshRateSelector::calculateLayerScoreLocked(const LayerRequirement& lay // If the layer frame rate is a divisor of the refresh rate it should score // the highest score. - if (getFrameRateDivisor(refreshRate, layer.desiredRefreshRate) > 0) { + if (layer.desiredRefreshRate.isValid() && + getFrameRateDivisor(refreshRate, layer.desiredRefreshRate) > 0) { return 1.0f * seamlessness; } @@ -441,6 +462,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi int explicitDefaultVoteLayers = 0; int explicitExactOrMultipleVoteLayers = 0; int explicitExact = 0; + int explicitCategoryVoteLayers = 0; int seamedFocusedLayers = 0; for (const auto& layer : layers) { @@ -463,6 +485,9 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi case LayerVoteType::ExplicitExact: explicitExact++; break; + case LayerVoteType::ExplicitCategory: + explicitCategoryVoteLayers++; + break; case LayerVoteType::Heuristic: break; } @@ -473,7 +498,8 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi } const bool hasExplicitVoteLayers = explicitDefaultVoteLayers > 0 || - explicitExactOrMultipleVoteLayers > 0 || explicitExact > 0; + explicitExactOrMultipleVoteLayers > 0 || explicitExact > 0 || + explicitCategoryVoteLayers > 0; const Policy* policy = getCurrentPolicyLocked(); const auto& defaultMode = mDisplayModes.get(policy->defaultMode)->get(); @@ -536,10 +562,11 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi } for (const auto& layer : layers) { - ALOGV("Calculating score for %s (%s, weight %.2f, desired %.2f) ", layer.name.c_str(), - ftl::enum_string(layer.vote).c_str(), layer.weight, - layer.desiredRefreshRate.getValue()); - if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min) { + ALOGV("Calculating score for %s (%s, weight %.2f, desired %.2f, category %s) ", + layer.name.c_str(), ftl::enum_string(layer.vote).c_str(), layer.weight, + layer.desiredRefreshRate.getValue(), + ftl::enum_string(layer.frameRateCategory).c_str()); + if (layer.isNoVote() || layer.vote == LayerVoteType::Min) { continue; } @@ -607,6 +634,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi case LayerVoteType::Max: case LayerVoteType::ExplicitDefault: case LayerVoteType::ExplicitExact: + case LayerVoteType::ExplicitCategory: return false; } }(layer.vote); @@ -722,7 +750,8 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi const auto touchRefreshRates = rankFrameRates(anchorGroup, RefreshRateOrder::Descending); using fps_approx_ops::operator<; - if (signals.touch && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact && + if (signals.touch && explicitDefaultVoteLayers == 0 && explicitCategoryVoteLayers == 0 && + touchBoostForExplicitExact && scores.front().frameRateMode.fps < touchRefreshRates.front().frameRateMode.fps) { ALOGV("Touch Boost"); ATRACE_FORMAT_INSTANT("%s (Touch Boost [late])", @@ -838,8 +867,10 @@ auto RefreshRateSelector::getFrameRateOverrides(const std::vector<LayerRequireme } LOG_ALWAYS_FATAL_IF(layer->vote != LayerVoteType::ExplicitDefault && - layer->vote != LayerVoteType::ExplicitExactOrMultiple && - layer->vote != LayerVoteType::ExplicitExact); + layer->vote != LayerVoteType::ExplicitExactOrMultiple && + layer->vote != LayerVoteType::ExplicitExact && + layer->vote != LayerVoteType::ExplicitCategory, + "Invalid layer vote type for frame rate overrides"); for (auto& [fps, score] : scoredFrameRates) { constexpr bool isSeamlessSwitch = true; const auto layerScore = calculateLayerScoreLocked(*layer, fps, isSeamlessSwitch); @@ -1380,6 +1411,27 @@ std::chrono::milliseconds RefreshRateSelector::getIdleTimerTimeout() { return mConfig.idleTimerTimeout; } +// TODO(b/293651105): Extract category FpsRange mapping to OEM-configurable config. +FpsRange RefreshRateSelector::getFrameRateCategoryRange(FrameRateCategory category) { + switch (category) { + case FrameRateCategory::High: + return FpsRange{90_Hz, 120_Hz}; + case FrameRateCategory::Normal: + return FpsRange{60_Hz, 90_Hz}; + case FrameRateCategory::Low: + return FpsRange{30_Hz, 60_Hz}; + case FrameRateCategory::NoPreference: + case FrameRateCategory::Default: + LOG_ALWAYS_FATAL("Should not get fps range for frame rate category: %s", + ftl::enum_string(category).c_str()); + return FpsRange{0_Hz, 0_Hz}; + default: + LOG_ALWAYS_FATAL("Invalid frame rate category for range: %s", + ftl::enum_string(category).c_str()); + return FpsRange{0_Hz, 0_Hz}; + } +} + } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h index 7af8d0397f..41db38d705 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h @@ -147,8 +147,9 @@ public: // ExactOrMultiple compatibility ExplicitExact, // Specific refresh rate that was provided by the app with // Exact compatibility + ExplicitCategory, // Specific frame rate category was provided by the app - ftl_last = ExplicitExact + ftl_last = ExplicitCategory }; // Captures the layer requirements for a refresh rate. This will be used to determine the @@ -164,6 +165,8 @@ public: Fps desiredRefreshRate; // If a seamless mode switch is required. Seamlessness seamlessness = Seamlessness::Default; + // Layer frame rate category. Superseded by desiredRefreshRate. + FrameRateCategory frameRateCategory = FrameRateCategory::Default; // Layer's weight in the range of [0, 1]. The higher the weight the more impact this layer // would have on choosing the refresh rate. float weight = 0.0f; @@ -174,12 +177,20 @@ public: return name == other.name && vote == other.vote && isApproxEqual(desiredRefreshRate, other.desiredRefreshRate) && seamlessness == other.seamlessness && weight == other.weight && - focused == other.focused; + focused == other.focused && frameRateCategory == other.frameRateCategory; } bool operator!=(const LayerRequirement& other) const { return !(*this == other); } + + bool isNoVote() const { return RefreshRateSelector::isNoVote(vote, frameRateCategory); } }; + // Returns true if the layer explicitly instructs to not contribute to refresh rate selection. + // In other words, true if the layer should be ignored. + static bool isNoVote(LayerVoteType vote, FrameRateCategory category) { + return vote == LayerVoteType::NoVote || category == FrameRateCategory::NoPreference; + } + // Global state describing signals that affect refresh rate choice. struct GlobalSignals { // Whether the user touched the screen recently. Used to apply touch boost. @@ -344,6 +355,9 @@ public: Fps displayFrameRate, GlobalSignals) const EXCLUDES(mLock); + // Gets the FpsRange that the FrameRateCategory represents. + static FpsRange getFrameRateCategoryRange(FrameRateCategory category); + std::optional<KernelIdleTimerController> kernelIdleTimerController() { return mConfig.kernelIdleTimerController; } @@ -447,6 +461,11 @@ private: float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&, Fps refreshRate) const REQUIRES(mLock); + // Calculates the score for non-exact matching layer that has LayerVoteType::ExplicitDefault. + float calculateNonExactMatchingDefaultLayerScoreLocked(nsecs_t displayPeriod, + nsecs_t layerPeriod) const + REQUIRES(mLock); + void updateDisplayModes(DisplayModes, DisplayModeId activeModeId) EXCLUDES(mLock) REQUIRES(kMainThreadContext); diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h index d6329e246c..19e951abb2 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h @@ -23,6 +23,7 @@ #include <type_traits> #include <android-base/stringprintf.h> +#include <ftl/enum.h> #include <scheduler/Time.h> namespace android { @@ -81,6 +82,17 @@ struct FpsRanges { bool valid() const; }; +// The frame rate category of a Layer. +enum class FrameRateCategory { + Default, + NoPreference, + Low, + Normal, + High, + + ftl_last = High +}; + static_assert(std::is_trivially_copyable_v<Fps>); constexpr Fps operator""_Hz(unsigned long long frequency) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 06adfec0d2..5c25dbce0c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5192,9 +5192,15 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime const auto strategy = Layer::FrameRate::convertChangeFrameRateStrategy(s.changeFrameRateStrategy); - if (layer->setFrameRate( - Layer::FrameRate(Fps::fromValue(s.frameRate), compatibility, strategy))) { - flags |= eTraversalNeeded; + if (layer->setFrameRate(Layer::FrameRate::FrameRateVote(Fps::fromValue(s.frameRate), + compatibility, strategy))) { + flags |= eTraversalNeeded; + } + } + if (what & layer_state_t::eFrameRateCategoryChanged) { + const FrameRateCategory category = Layer::FrameRate::convertCategory(s.frameRateCategory); + if (layer->setFrameRateCategory(category)) { + flags |= eTraversalNeeded; } } if (what & layer_state_t::eFixedTransformHintChanged) { diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h index f64ba2a439..93438d8666 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h @@ -335,6 +335,17 @@ protected: mLifecycleManager.applyTransactions(transactions); } + void setFrameRateCategory(uint32_t id, int8_t frameRateCategory) { + std::vector<TransactionState> transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + + transactions.back().states.front().state.what = layer_state_t::eFrameRateCategoryChanged; + transactions.back().states.front().layerId = id; + transactions.back().states.front().state.frameRateCategory = frameRateCategory; + mLifecycleManager.applyTransactions(transactions); + } + void setRoundedCorners(uint32_t id, float radius) { std::vector<TransactionState> transactions; transactions.emplace_back(); diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 85d86a7acc..51b5b05bed 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -437,6 +437,117 @@ TEST_F(LayerHistoryTest, oneLayerExplicitExactVote) { EXPECT_EQ(0, frequentLayerCount(time)); } +TEST_F(LayerHistoryTest, oneLayerExplicitCategory) { + auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()) + .WillRepeatedly( + Return(Layer::FrameRate(0_Hz, Layer::FrameRateCompatibility::Default, + Seamlessness::OnlySeamless, FrameRateCategory::High))); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + history().record(layer->getSequence(), layer->getLayerProps(), time, time, + LayerHistory::LayerUpdateType::Buffer); + time += HI_FPS_PERIOD; + } + + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + // First LayerRequirement is the frame rate specification + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory); + + // layer became inactive, but the vote stays + setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); + time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory); +} + +// This test case should be the same as oneLayerNoVote except instead of layer vote is NoVote, +// the category is NoPreference. +TEST_F(LayerHistoryTest, oneLayerCategoryNoPreference) { + auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()) + .WillRepeatedly(Return(Layer::FrameRate(0_Hz, Layer::FrameRateCompatibility::Default, + Seamlessness::OnlySeamless, + FrameRateCategory::NoPreference))); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + history().record(layer->getSequence(), layer->getLayerProps(), time, time, + LayerHistory::LayerUpdateType::Buffer); + time += HI_FPS_PERIOD; + } + + ASSERT_TRUE(summarizeLayerHistory(time).empty()); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + + // layer became inactive + time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); + ASSERT_TRUE(summarizeLayerHistory(time).empty()); + EXPECT_EQ(0, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); +} + +TEST_F(LayerHistoryTest, oneLayerExplicitVoteWithCategory) { + auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()) + .WillRepeatedly( + Return(Layer::FrameRate(73.4_Hz, Layer::FrameRateCompatibility::Default, + Seamlessness::OnlySeamless, FrameRateCategory::High))); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + history().record(layer->getSequence(), layer->getLayerProps(), time, time, + LayerHistory::LayerUpdateType::Buffer); + time += HI_FPS_PERIOD; + } + + // There are 2 LayerRequirement's due to the frame rate category. + ASSERT_EQ(2, summarizeLayerHistory(time).size()); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + // First LayerRequirement is the layer's category specification + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory); + + // Second LayerRequirement is the frame rate specification + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[1].vote); + EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[1].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[1].frameRateCategory); + + // layer became inactive, but the vote stays + setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); + time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); + ASSERT_EQ(2, summarizeLayerHistory(time).size()); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory); +} + TEST_F(LayerHistoryTest, multipleLayers) { auto layer1 = createLayer("A"); auto layer2 = createLayer("B"); diff --git a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp index 5c2d2e1f43..e0133d6010 100644 --- a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp @@ -24,13 +24,23 @@ #include "FpsOps.h" #include "Scheduler/LayerHistory.h" #include "Scheduler/LayerInfo.h" +#include "TestableScheduler.h" +#include "TestableSurfaceFlinger.h" +#include "mock/MockSchedulerCallback.h" namespace android::scheduler { +using android::mock::createDisplayMode; + class LayerInfoTest : public testing::Test { protected: using FrameTimeData = LayerInfo::FrameTimeData; + static constexpr Fps LO_FPS = 30_Hz; + static constexpr Fps HI_FPS = 90_Hz; + + LayerInfoTest() { mFlinger.resetScheduler(mScheduler); } + void setFrameTimes(const std::deque<FrameTimeData>& frameTimes) { layerInfo.mFrameTimes = frameTimes; } @@ -43,6 +53,16 @@ protected: auto calculateAverageFrameTime() { return layerInfo.calculateAverageFrameTime(); } LayerInfo layerInfo{"TestLayerInfo", 0, LayerHistory::LayerVoteType::Heuristic}; + + std::shared_ptr<RefreshRateSelector> mSelector = + std::make_shared<RefreshRateSelector>(makeModes(createDisplayMode(DisplayModeId(0), + LO_FPS), + createDisplayMode(DisplayModeId(1), + HI_FPS)), + DisplayModeId(0)); + mock::SchedulerCallback mSchedulerCallback; + TestableScheduler* mScheduler = new TestableScheduler(mSelector, mSchedulerCallback); + TestableSurfaceFlinger mFlinger; }; namespace { @@ -171,5 +191,63 @@ TEST_F(LayerInfoTest, ignoresLargePeriods) { ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime)); } +TEST_F(LayerInfoTest, getRefreshRateVote_explicitVote) { + LayerInfo::LayerVote vote = {.type = LayerHistory::LayerVoteType::ExplicitDefault, + .fps = 20_Hz}; + layerInfo.setLayerVote(vote); + + auto actualVotes = + layerInfo.getRefreshRateVote(*mScheduler->refreshRateSelector(), systemTime()); + ASSERT_EQ(actualVotes.size(), 1u); + ASSERT_EQ(actualVotes[0].type, vote.type); + ASSERT_EQ(actualVotes[0].fps, vote.fps); + ASSERT_EQ(actualVotes[0].seamlessness, vote.seamlessness); + ASSERT_EQ(actualVotes[0].category, vote.category); +} + +TEST_F(LayerInfoTest, getRefreshRateVote_explicitVoteWithCategory) { + LayerInfo::LayerVote vote = {.type = LayerHistory::LayerVoteType::ExplicitDefault, + .fps = 20_Hz, + .category = FrameRateCategory::High}; + layerInfo.setLayerVote(vote); + + auto actualVotes = + layerInfo.getRefreshRateVote(*mScheduler->refreshRateSelector(), systemTime()); + ASSERT_EQ(actualVotes.size(), 2u); + ASSERT_EQ(actualVotes[0].type, LayerHistory::LayerVoteType::ExplicitCategory); + ASSERT_EQ(actualVotes[0].category, vote.category); + ASSERT_EQ(actualVotes[1].type, vote.type); + ASSERT_EQ(actualVotes[1].fps, vote.fps); + ASSERT_EQ(actualVotes[1].seamlessness, vote.seamlessness); + ASSERT_EQ(actualVotes[1].category, vote.category); +} + +TEST_F(LayerInfoTest, getRefreshRateVote_explicitCategory) { + // When a layer only has a category set, the LayerVoteType should be the LayerInfo's default. + // The most common case should be Heuristic. + LayerInfo::LayerVote vote = {.type = LayerHistory::LayerVoteType::ExplicitDefault, + .category = FrameRateCategory::High}; + layerInfo.setLayerVote(vote); + + auto actualVotes = + layerInfo.getRefreshRateVote(*mScheduler->refreshRateSelector(), systemTime()); + ASSERT_EQ(actualVotes.size(), 1u); + ASSERT_EQ(actualVotes[0].type, LayerHistory::LayerVoteType::ExplicitCategory); + ASSERT_EQ(actualVotes[0].category, vote.category); +} + +TEST_F(LayerInfoTest, getRefreshRateVote_noData) { + LayerInfo::LayerVote vote = { + .type = LayerHistory::LayerVoteType::Heuristic, + }; + layerInfo.setLayerVote(vote); + + auto actualVotes = + layerInfo.getRefreshRateVote(*mScheduler->refreshRateSelector(), systemTime()); + ASSERT_EQ(actualVotes.size(), 1u); + ASSERT_EQ(actualVotes[0].type, LayerHistory::LayerVoteType::Max); + ASSERT_EQ(actualVotes[0].fps, vote.fps); +} + } // namespace } // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 84c37759ba..67cd4c67eb 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -314,13 +314,15 @@ TEST_F(LayerSnapshotTest, NoLayerVoteForParentWithChildVotes) { mLifecycleManager.applyTransactions(transactions); UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); - EXPECT_EQ(getSnapshot(11)->frameRate.rate.getIntValue(), 90); - EXPECT_EQ(getSnapshot(11)->frameRate.type, scheduler::LayerInfo::FrameRateCompatibility::Exact); - EXPECT_EQ(getSnapshot(111)->frameRate.rate.getIntValue(), 90); - EXPECT_EQ(getSnapshot(111)->frameRate.type, + EXPECT_EQ(getSnapshot(11)->frameRate.vote.rate.getIntValue(), 90); + EXPECT_EQ(getSnapshot(11)->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Exact); - EXPECT_EQ(getSnapshot(1)->frameRate.rate.getIntValue(), 0); - EXPECT_EQ(getSnapshot(1)->frameRate.type, scheduler::LayerInfo::FrameRateCompatibility::NoVote); + EXPECT_EQ(getSnapshot(111)->frameRate.vote.rate.getIntValue(), 90); + EXPECT_EQ(getSnapshot(111)->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Exact); + EXPECT_EQ(getSnapshot(1)->frameRate.vote.rate.getIntValue(), 0); + EXPECT_EQ(getSnapshot(1)->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::NoVote); } TEST_F(LayerSnapshotTest, CanCropTouchableRegion) { @@ -525,21 +527,21 @@ TEST_F(LayerSnapshotTest, framerate) { UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); // verify parent is gets no vote - EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 1})->frameRate.type, + EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::NoVote); EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate)); // verify layer and children get the requested votes - EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 11})->frameRate.rate.getValue(), 244.f); - EXPECT_EQ(getSnapshot({.id = 11})->frameRate.type, + EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 11})->changes.test(RequestedLayerState::Changes::FrameRate)); - EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 111})->frameRate.rate.getValue(), 244.f); - EXPECT_EQ(getSnapshot({.id = 111})->frameRate.type, + EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 111})->changes.test(RequestedLayerState::Changes::FrameRate)); @@ -549,24 +551,24 @@ TEST_F(LayerSnapshotTest, framerate) { std::vector<uint32_t> expected = {1, 11, 111, 122, 1221, 12, 121, 13, 2}; UPDATE_AND_VERIFY(mSnapshotBuilder, expected); // verify parent is gets no vote - EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 1})->frameRate.type, + EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::NoVote); // verify layer and children get the requested votes - EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 11})->frameRate.rate.getValue(), 244.f); - EXPECT_EQ(getSnapshot({.id = 11})->frameRate.type, + EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); - EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 111})->frameRate.rate.getValue(), 244.f); - EXPECT_EQ(getSnapshot({.id = 111})->frameRate.type, + EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); - EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 122})->frameRate.rate.getValue(), 244.f); - EXPECT_EQ(getSnapshot({.id = 122})->frameRate.type, + EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 122})->changes.test(RequestedLayerState::Changes::FrameRate)); @@ -576,31 +578,31 @@ TEST_F(LayerSnapshotTest, framerate) { UPDATE_AND_VERIFY(mSnapshotBuilder, expected); // verify old parent has invalid framerate (default) - EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 1})->frameRate.type, + EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate)); // verify new parent get no vote - EXPECT_FALSE(getSnapshot({.id = 2})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 2})->frameRate.type, + EXPECT_FALSE(getSnapshot({.id = 2})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 2})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::NoVote); EXPECT_TRUE(getSnapshot({.id = 2})->changes.test(RequestedLayerState::Changes::FrameRate)); // verify layer and children get the requested votes (unchanged) - EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 11})->frameRate.rate.getValue(), 244.f); - EXPECT_EQ(getSnapshot({.id = 11})->frameRate.type, + EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); - EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 111})->frameRate.rate.getValue(), 244.f); - EXPECT_EQ(getSnapshot({.id = 111})->frameRate.type, + EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); - EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 122})->frameRate.rate.getValue(), 244.f); - EXPECT_EQ(getSnapshot({.id = 122})->frameRate.type, + EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); } @@ -610,6 +612,112 @@ TEST_F(LayerSnapshotTest, translateDataspace) { EXPECT_EQ(getSnapshot({.id = 1})->dataspace, ui::Dataspace::V0_SRGB); } +// This test is similar to "frameRate" test case but checks that the setFrameRateCategory API +// interaction also works correctly with the setFrameRate API within SF frontend. +TEST_F(LayerSnapshotTest, frameRateWithCategory) { + // ROOT + // ├── 1 + // │ ├── 11 (frame rate set to 244.f) + // │ │ └── 111 + // │ ├── 12 + // │ │ ├── 121 + // │ │ └── 122 (frame rate category set to Normal) + // │ │ └── 1221 + // │ └── 13 + // └── 2 + setFrameRate(11, 244.f, 0, 0); + setFrameRateCategory(122, 3 /* Normal */); + + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + // verify parent 1 gets no vote + EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::NoVote); + EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate)); + + // verify layer 11 and children 111 get the requested votes + EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + EXPECT_TRUE(getSnapshot({.id = 11})->changes.test(RequestedLayerState::Changes::FrameRate)); + + EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + EXPECT_TRUE(getSnapshot({.id = 111})->changes.test(RequestedLayerState::Changes::FrameRate)); + + // verify parent 12 gets no vote + EXPECT_FALSE(getSnapshot({.id = 12})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 12})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::NoVote); + EXPECT_TRUE(getSnapshot({.id = 12})->changes.test(RequestedLayerState::Changes::FrameRate)); + + // verify layer 122 and children 1221 get the requested votes + EXPECT_FALSE(getSnapshot({.id = 122})->frameRate.vote.rate.isValid()); + EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.isValid()); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.category, FrameRateCategory::Normal); + EXPECT_TRUE(getSnapshot({.id = 122})->changes.test(RequestedLayerState::Changes::FrameRate)); + + EXPECT_FALSE(getSnapshot({.id = 1221})->frameRate.vote.rate.isValid()); + EXPECT_TRUE(getSnapshot({.id = 1221})->frameRate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.category, FrameRateCategory::Normal); + EXPECT_TRUE(getSnapshot({.id = 1221})->changes.test(RequestedLayerState::Changes::FrameRate)); + + // reparent and verify the child does NOT get the new parent's framerate because it already has + // the frame rate category specified. + // ROOT + // ├─1 + // │ ├─11 (frame rate set to 244.f) + // │ │ ├─111 + // │ │ └─122 (frame rate category set to Normal) + // │ │ └─1221 + // │ ├─12 + // │ │ └─121 + // │ └─13 + // └─2 + reparentLayer(122, 11); + + std::vector<uint32_t> expected = {1, 11, 111, 122, 1221, 12, 121, 13, 2}; + UPDATE_AND_VERIFY(mSnapshotBuilder, expected); + // verify parent is gets no vote + EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::NoVote); + + // verify layer 11 and children 111 get the requested votes + EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + + EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + + // verify layer 122 and children 1221 get the requested category vote (unchanged from + // reparenting) + EXPECT_FALSE(getSnapshot({.id = 122})->frameRate.vote.rate.isValid()); + EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.isValid()); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.category, FrameRateCategory::Normal); + EXPECT_TRUE(getSnapshot({.id = 122})->changes.test(RequestedLayerState::Changes::FrameRate)); + + EXPECT_FALSE(getSnapshot({.id = 1221})->frameRate.vote.rate.isValid()); + EXPECT_TRUE(getSnapshot({.id = 1221})->frameRate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.category, FrameRateCategory::Normal); + EXPECT_TRUE(getSnapshot({.id = 1221})->changes.test(RequestedLayerState::Changes::FrameRate)); +} + TEST_F(LayerSnapshotTest, skipRoundCornersWhenProtected) { setRoundedCorners(1, 42.f); setRoundedCorners(2, 42.f); diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index aaf55fbeae..dc6b70032a 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -26,6 +26,7 @@ #include <log/log.h> #include <ui/Size.h> +#include <scheduler/Fps.h> #include <scheduler/FrameRateMode.h> #include "DisplayHardware/HWC2.h" #include "FpsOps.h" @@ -1381,6 +1382,120 @@ TEST_P(RefreshRateSelectorTest, touchConsidered) { EXPECT_FALSE(signals.touch); } +TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_30_60_90_120) { + auto selector = createSelector(makeModes(kMode30, kMode60, kMode90, kMode120), kModeId60); + + std::vector<LayerRequirement> layers = {{.vote = LayerVoteType::ExplicitDefault, .weight = 1.f}, + {.vote = LayerVoteType::ExplicitCategory, + .weight = 1.f}}; + auto& lr = layers[0]; + + struct Case { + // Params + Fps desiredFrameRate = 0_Hz; + FrameRateCategory frameRateCategory = FrameRateCategory::Default; + + // Expected result + Fps expectedFrameRate = 0_Hz; + }; + + // Prepare a table with the vote and the expected refresh rate + const std::initializer_list<Case> testCases = { + // Cases that only have frame rate category requirements, but no desired frame rate. + // When frame rates get an equal score, the lower is chosen, unless there are Max votes. + {0_Hz, FrameRateCategory::High, 90_Hz}, + {0_Hz, FrameRateCategory::Normal, 60_Hz}, + {0_Hz, FrameRateCategory::Low, 30_Hz}, + {0_Hz, FrameRateCategory::NoPreference, 60_Hz}, + + // Cases that have both desired frame rate and frame rate category requirements. + {24_Hz, FrameRateCategory::High, 120_Hz}, + {30_Hz, FrameRateCategory::High, 90_Hz}, + {12_Hz, FrameRateCategory::Normal, 60_Hz}, + {30_Hz, FrameRateCategory::NoPreference, 30_Hz}, + + // Cases that only have desired frame rate. + {30_Hz, FrameRateCategory::Default, 30_Hz}, + }; + + for (auto testCase : testCases) { + ALOGI("**** %s: Testing desiredFrameRate=%s, frameRateCategory=%s", __func__, + to_string(testCase.desiredFrameRate).c_str(), + ftl::enum_string(testCase.frameRateCategory).c_str()); + + lr.desiredRefreshRate = testCase.desiredFrameRate; + + std::stringstream ss; + ss << to_string(testCase.desiredFrameRate) + << ", category=" << ftl::enum_string(testCase.frameRateCategory); + lr.name = ss.str(); + + if (testCase.frameRateCategory != FrameRateCategory::Default) { + layers[1].frameRateCategory = testCase.frameRateCategory; + } + + EXPECT_EQ(testCase.expectedFrameRate, selector.getBestFrameRateMode(layers)->getFps()) + << "did not get expected frame rate for " << lr.name; + } +} + +TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_60_120) { + auto selector = createSelector(makeModes(kMode60, kMode120), kModeId60); + + std::vector<LayerRequirement> layers = {{.vote = LayerVoteType::ExplicitDefault, .weight = 1.f}, + {.vote = LayerVoteType::ExplicitCategory, + .weight = 1.f}}; + auto& lr = layers[0]; + + struct Case { + // Params + Fps desiredFrameRate = 0_Hz; + FrameRateCategory frameRateCategory = FrameRateCategory::Default; + + // Expected result + Fps expectedFrameRate = 0_Hz; + }; + + // Prepare a table with the vote and the expected refresh rate + const std::initializer_list<Case> testCases = { + // Cases that only have frame rate category requirements, but no desired frame rate. + // When frame rates get an equal score, the lower is chosen, unless there are Max votes. + {0_Hz, FrameRateCategory::High, 120_Hz}, + {0_Hz, FrameRateCategory::Normal, 60_Hz}, + {0_Hz, FrameRateCategory::Low, 60_Hz}, + {0_Hz, FrameRateCategory::NoPreference, 60_Hz}, + + // Cases that have both desired frame rate and frame rate category requirements. + {24_Hz, FrameRateCategory::High, 120_Hz}, + {30_Hz, FrameRateCategory::High, 120_Hz}, + {12_Hz, FrameRateCategory::Normal, 60_Hz}, + {30_Hz, FrameRateCategory::NoPreference, 60_Hz}, + + // Cases that only have desired frame rate. + {30_Hz, FrameRateCategory::Default, 60_Hz}, + }; + + for (auto testCase : testCases) { + ALOGI("**** %s: Testing desiredFrameRate=%s, frameRateCategory=%s", __func__, + to_string(testCase.desiredFrameRate).c_str(), + ftl::enum_string(testCase.frameRateCategory).c_str()); + + lr.desiredRefreshRate = testCase.desiredFrameRate; + + std::stringstream ss; + ss << to_string(testCase.desiredFrameRate) + << ", category=" << ftl::enum_string(testCase.frameRateCategory); + lr.name = ss.str(); + + if (testCase.frameRateCategory != FrameRateCategory::Default) { + layers[1].frameRateCategory = testCase.frameRateCategory; + } + + EXPECT_EQ(testCase.expectedFrameRate, selector.getBestFrameRateMode(layers)->getFps()) + << "did not get expected frame rate for " << lr.name; + } +} + TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_ExplicitDefault) { auto selector = createSelector(kModes_60_90_72_120, kModeId60); diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index a1e4e25c06..608fa762ef 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -97,7 +97,7 @@ TEST_P(SetFrameRateTest, SetAndGet) { const auto& layerFactory = GetParam(); auto layer = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); - layer->setFrameRate(FRAME_RATE_VOTE1); + layer->setFrameRate(FRAME_RATE_VOTE1.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE1, layer->getFrameRateForLayerTree()); } @@ -114,13 +114,13 @@ TEST_P(SetFrameRateTest, SetAndGetParent) { addChild(parent, child1); addChild(child1, child2); - child2->setFrameRate(FRAME_RATE_VOTE1); + child2->setFrameRate(FRAME_RATE_VOTE1.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); - child2->setFrameRate(FRAME_RATE_NO_VOTE); + child2->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); @@ -139,27 +139,27 @@ TEST_P(SetFrameRateTest, SetAndGetParentAllVote) { addChild(parent, child1); addChild(child1, child2); - child2->setFrameRate(FRAME_RATE_VOTE1); - child1->setFrameRate(FRAME_RATE_VOTE2); - parent->setFrameRate(FRAME_RATE_VOTE3); + child2->setFrameRate(FRAME_RATE_VOTE1.vote); + child1->setFrameRate(FRAME_RATE_VOTE2.vote); + parent->setFrameRate(FRAME_RATE_VOTE3.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); - child2->setFrameRate(FRAME_RATE_NO_VOTE); + child2->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE2, child2->getFrameRateForLayerTree()); - child1->setFrameRate(FRAME_RATE_NO_VOTE); + child1->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE3, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE3, child2->getFrameRateForLayerTree()); - parent->setFrameRate(FRAME_RATE_NO_VOTE); + parent->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); @@ -178,13 +178,13 @@ TEST_P(SetFrameRateTest, SetAndGetChild) { addChild(parent, child1); addChild(child1, child2); - parent->setFrameRate(FRAME_RATE_VOTE1); + parent->setFrameRate(FRAME_RATE_VOTE1.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); - parent->setFrameRate(FRAME_RATE_NO_VOTE); + parent->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); @@ -203,27 +203,27 @@ TEST_P(SetFrameRateTest, SetAndGetChildAllVote) { addChild(parent, child1); addChild(child1, child2); - child2->setFrameRate(FRAME_RATE_VOTE1); - child1->setFrameRate(FRAME_RATE_VOTE2); - parent->setFrameRate(FRAME_RATE_VOTE3); + child2->setFrameRate(FRAME_RATE_VOTE1.vote); + child1->setFrameRate(FRAME_RATE_VOTE2.vote); + parent->setFrameRate(FRAME_RATE_VOTE3.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); - parent->setFrameRate(FRAME_RATE_NO_VOTE); + parent->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); - child1->setFrameRate(FRAME_RATE_NO_VOTE); + child1->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); - child2->setFrameRate(FRAME_RATE_NO_VOTE); + child2->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); @@ -241,7 +241,7 @@ TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) { addChild(parent, child1); - parent->setFrameRate(FRAME_RATE_VOTE1); + parent->setFrameRate(FRAME_RATE_VOTE1.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree()); @@ -253,7 +253,7 @@ TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) { EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); - parent->setFrameRate(FRAME_RATE_NO_VOTE); + parent->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); @@ -272,7 +272,7 @@ TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) { addChild(parent, child1); addChild(child1, child2); - parent->setFrameRate(FRAME_RATE_VOTE1); + parent->setFrameRate(FRAME_RATE_VOTE1.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree()); @@ -284,7 +284,7 @@ TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) { EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); - parent->setFrameRate(FRAME_RATE_NO_VOTE); + parent->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); @@ -305,14 +305,14 @@ TEST_P(SetFrameRateTest, SetAndGetParentNotInTree) { addChild(child1, child2); addChild(child1, child2_1); - child2->setFrameRate(FRAME_RATE_VOTE1); + child2->setFrameRate(FRAME_RATE_VOTE1.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child2_1->getFrameRateForLayerTree()); - child2->setFrameRate(FRAME_RATE_NO_VOTE); + child2->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); @@ -375,7 +375,7 @@ TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { auto child = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); addChild(parent, child); - parent->setFrameRate(FRAME_RATE_VOTE1); + parent->setFrameRate(FRAME_RATE_VOTE1.vote); commitTransaction(); auto& history = mFlinger.mutableScheduler().mutableLayerHistory(); @@ -388,8 +388,8 @@ TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { const auto summary = history.summarize(*selectorPtr, 0); ASSERT_EQ(2u, summary.size()); - EXPECT_EQ(FRAME_RATE_VOTE1.rate, summary[0].desiredRefreshRate); - EXPECT_EQ(FRAME_RATE_VOTE1.rate, summary[1].desiredRefreshRate); + EXPECT_EQ(FRAME_RATE_VOTE1.vote.rate, summary[0].desiredRefreshRate); + EXPECT_EQ(FRAME_RATE_VOTE1.vote.rate, summary[1].desiredRefreshRate); } TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) { @@ -405,7 +405,7 @@ TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) { addChild(parent, child1); addChild(child1, childOfChild1); - childOfChild1->setFrameRate(FRAME_RATE_VOTE1); + childOfChild1->setFrameRate(FRAME_RATE_VOTE1.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); @@ -419,7 +419,7 @@ TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) { EXPECT_EQ(FRAME_RATE_VOTE1, childOfChild1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); - childOfChild1->setFrameRate(FRAME_RATE_NO_VOTE); + childOfChild1->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); |