From aae5ed5b7ad78f4a6fba62556d875ae95e7f9987 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 26 Jun 2020 09:32:43 -0700 Subject: SurfaceFlinger: only focused layers can use appRequestRange When DisplayManager sets the DisplayConfigsSpecs with a policy that the appRequestRange is broader than the primaryRange, it means that an app can choose a refresh rate from the appRequestRange and not from the primaryRange only if that app explicitly specified a frame rate using setFrameRate API. However, to avoid cases where we switch the refresh rate back and forth from the two ranges, we are allowing only applications that their window is focused from WindowManager's perspective to select refresh rate out the primaryRange. This matches the behavior of an application that sets the preferredDisplayModeId. Bug: 144307188 Bug: 159940172 Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest Test: YouTube in PIP mode while device is restricted by primaryRange Change-Id: I26a9690210bb5771bd8aae2bff301031617f7c8f --- services/surfaceflinger/Layer.cpp | 19 ++++++--- services/surfaceflinger/Layer.h | 10 +++++ services/surfaceflinger/Scheduler/LayerHistory.cpp | 7 +++- .../surfaceflinger/Scheduler/LayerHistoryV2.cpp | 9 +++-- .../Scheduler/RefreshRateConfigs.cpp | 9 +++-- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 19 ++++++--- .../tests/unittests/RefreshRateConfigsTest.cpp | 47 ++++++++++++++++++++-- 7 files changed, 94 insertions(+), 26 deletions(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 13049eddf2..03903f6d07 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1325,6 +1325,10 @@ int32_t Layer::getFrameRateSelectionPriority() const { return Layer::PRIORITY_UNSET; } +bool Layer::isLayerFocusedBasedOnPriority(int32_t priority) { + return priority == PRIORITY_FOCUSED_WITH_MODE || priority == PRIORITY_FOCUSED_WITHOUT_MODE; +}; + uint32_t Layer::getLayerStack() const { auto p = mDrawingParent.promote(); if (p == nullptr) { @@ -1558,7 +1562,7 @@ void Layer::miniDumpHeader(std::string& result) { result.append("-------------------------------"); result.append("-------------------------------"); result.append("-------------------------------"); - result.append("---------\n"); + result.append("-------------------\n"); result.append(" Layer name\n"); result.append(" Z | "); result.append(" Window Type | "); @@ -1566,12 +1570,12 @@ void Layer::miniDumpHeader(std::string& result) { result.append(" Transform | "); result.append(" Disp Frame (LTRB) | "); result.append(" Source Crop (LTRB) | "); - result.append(" Frame Rate (Explicit)\n"); + result.append(" Frame Rate (Explicit) [Focused]\n"); result.append("-------------------------------"); result.append("-------------------------------"); result.append("-------------------------------"); result.append("-------------------------------"); - result.append("---------\n"); + result.append("-------------------\n"); } std::string Layer::frameRateCompatibilityString(Layer::FrameRateCompatibility compatibility) { @@ -1622,17 +1626,20 @@ void Layer::miniDump(std::string& result, const DisplayDevice& display) const { crop.bottom); if (layerState.frameRate.rate != 0 || layerState.frameRate.type != FrameRateCompatibility::Default) { - StringAppendF(&result, "% 6.2ffps %15s\n", layerState.frameRate.rate, + StringAppendF(&result, "% 6.2ffps %15s", layerState.frameRate.rate, frameRateCompatibilityString(layerState.frameRate.type).c_str()); } else { - StringAppendF(&result, "\n"); + StringAppendF(&result, " "); } + const auto focused = isLayerFocusedBasedOnPriority(getFrameRateSelectionPriority()); + StringAppendF(&result, " [%s]\n", focused ? "*" : " "); + result.append("- - - - - - - - - - - - - - - - "); result.append("- - - - - - - - - - - - - - - - "); result.append("- - - - - - - - - - - - - - - - "); result.append("- - - - - - - - - - - - - - - - "); - result.append("- - -\n"); + result.append("- - - - - - - -\n"); } void Layer::dumpFrameStats(std::string& result) const { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 068424bd80..2c90c92f6c 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -94,7 +94,16 @@ struct LayerCreationArgs { class Layer : public virtual RefBase, compositionengine::LayerFE { static std::atomic sSequence; + // The following constants represent priority of the window. SF uses this information when + // deciding which window has a priority when deciding about the refresh rate of the screen. + // Priority 0 is considered the highest priority. -1 means that the priority is unset. static constexpr int32_t PRIORITY_UNSET = -1; + // Windows that are in focus and voted for the preferred mode ID + static constexpr int32_t PRIORITY_FOCUSED_WITH_MODE = 0; + // // Windows that are in focus, but have not requested a specific mode ID. + static constexpr int32_t PRIORITY_FOCUSED_WITHOUT_MODE = 1; + // Windows that are not in focus, but voted for a specific mode ID. + static constexpr int32_t PRIORITY_NOT_FOCUSED_WITH_MODE = 2; public: mutable bool contentDirty{false}; @@ -400,6 +409,7 @@ public: // If the variable is not set on the layer, it traverses up the tree to inherit the frame // rate priority from its parent. virtual int32_t getFrameRateSelectionPriority() const; + static bool isLayerFocusedBasedOnPriority(int32_t priority); virtual ui::Dataspace getDataSpace() const { return ui::Dataspace::UNKNOWN; } diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 292510978d..ecf2597b8c 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -109,6 +109,8 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { auto layer = weakLayer.promote(); // Only use the layer if the reference still exists. if (layer || CC_UNLIKELY(mTraceEnabled)) { + const auto layerFocused = + Layer::isLayerFocusedBasedOnPriority(layer->getFrameRateSelectionPriority()); // Check if frame rate was set on layer. const auto frameRate = layer->getFrameRateForLayerTree(); if (frameRate.rate > 0.f) { @@ -122,11 +124,12 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { return LayerVoteType::NoVote; } }(); - summary.push_back({layer->getName(), voteType, frameRate.rate, /* weight */ 1.0f}); + summary.push_back({layer->getName(), voteType, frameRate.rate, /* weight */ 1.0f, + layerFocused}); } else if (recent) { summary.push_back({layer->getName(), LayerVoteType::Heuristic, info->getRefreshRate(now), - /* weight */ 1.0f}); + /* weight */ 1.0f, layerFocused}); } if (CC_UNLIKELY(mTraceEnabled)) { diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp index ee612b0732..aa04bd7a58 100644 --- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp @@ -125,9 +125,10 @@ LayerHistoryV2::Summary LayerHistoryV2::summarize(nsecs_t now) { continue; } - // TODO(b/144307188): This needs to be plugged into layer summary as - // an additional parameter. - ALOGV("Layer has priority: %d", strong->getFrameRateSelectionPriority()); + const auto frameRateSelectionPriority = strong->getFrameRateSelectionPriority(); + const auto layerFocused = Layer::isLayerFocusedBasedOnPriority(frameRateSelectionPriority); + ALOGV("%s has priority: %d %s focused", strong->getName().c_str(), + frameRateSelectionPriority, layerFocused ? "" : "not"); const auto [type, refreshRate] = info->getRefreshRate(now); // Skip NoVote layer as those don't have any requirements @@ -143,7 +144,7 @@ LayerHistoryV2::Summary LayerHistoryV2::summarize(nsecs_t now) { const float layerArea = transformed.getWidth() * transformed.getHeight(); float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f; - summary.push_back({strong->getName(), type, refreshRate, weight}); + summary.push_back({strong->getName(), type, refreshRate, weight, layerFocused}); if (CC_UNLIKELY(mTraceEnabled)) { trace(layer, *info, type, static_cast(std::round(refreshRate))); diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index a6036c6b37..053d0a7a39 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -212,10 +212,11 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( bool inPrimaryRange = scores[i].first->inPolicy(policy->primaryRange.min, policy->primaryRange.max); if ((primaryRangeIsSingleRate || !inPrimaryRange) && - layer.vote != LayerVoteType::ExplicitDefault && - layer.vote != LayerVoteType::ExplicitExactOrMultiple) { - // Only layers with explicit frame rate settings are allowed to score refresh rates - // outside the primary range. + !(layer.focused && + (layer.vote == LayerVoteType::ExplicitDefault || + layer.vote == LayerVoteType::ExplicitExactOrMultiple))) { + // Only focused layers with explicit frame rate settings are allowed to score + // refresh rates outside the primary range. continue; } diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 8a51b85207..27bf0ecf9f 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -195,15 +195,22 @@ public: // Captures the layer requirements for a refresh rate. This will be used to determine the // display refresh rate. struct LayerRequirement { - std::string name; // Layer's name. Used for debugging purposes. - LayerVoteType vote; // Layer vote type. - float desiredRefreshRate; // Layer's desired refresh rate, if applicable. - float weight; // 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. + // Layer's name. Used for debugging purposes. + std::string name; + // Layer vote type. + LayerVoteType vote = LayerVoteType::NoVote; + // Layer's desired refresh rate, if applicable. + float desiredRefreshRate = 0.0f; + // 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; + // Whether layer is in focus or not based on WindowManager's state + bool focused = false; bool operator==(const LayerRequirement& other) const { return name == other.name && vote == other.vote && - desiredRefreshRate == other.desiredRefreshRate && weight == other.weight; + desiredRefreshRate == other.desiredRefreshRate && weight == other.weight && + focused == other.focused; } bool operator!=(const LayerRequirement& other) const { return !(*this == other); } diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index fed591cb19..03d4460b15 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -292,7 +292,8 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { /*currentConfigId=*/HWC_CONFIG_ID_60); const auto makeLayerRequirements = [](float refreshRate) -> std::vector { - return {{"testLayer", LayerVoteType::Heuristic, refreshRate, 1.0f}}; + return {{"testLayer", LayerVoteType::Heuristic, refreshRate, /*weight*/ 1.0f, + /*focused*/ false}}; }; EXPECT_EQ(mExpected90Config, @@ -1132,6 +1133,7 @@ TEST_F(RefreshRateConfigsTest, lr.vote = LayerVoteType::ExplicitExactOrMultiple; lr.desiredRefreshRate = 60.0f; lr.name = "60Hz ExplicitExactOrMultiple"; + lr.focused = true; EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = true}, &consideredSignals)); @@ -1140,6 +1142,7 @@ TEST_F(RefreshRateConfigsTest, lr.vote = LayerVoteType::ExplicitDefault; lr.desiredRefreshRate = 60.0f; lr.name = "60Hz ExplicitDefault"; + lr.focused = true; EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = true}, &consideredSignals)); @@ -1162,18 +1165,20 @@ TEST_F(RefreshRateConfigsTest, lr.vote = LayerVoteType::ExplicitExactOrMultiple; lr.desiredRefreshRate = 90.0f; lr.name = "90Hz ExplicitExactOrMultiple"; + lr.focused = true; EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = true})); lr.vote = LayerVoteType::ExplicitDefault; lr.desiredRefreshRate = 90.0f; lr.name = "90Hz ExplicitDefault"; + lr.focused = true; EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = true})); } TEST_F(RefreshRateConfigsTest, - getBestRefreshRate_withDisplayManagerRequestingSingleRate_onlySwitchesRatesForExplicitLayers) { + getBestRefreshRate_withDisplayManagerRequestingSingleRate_onlySwitchesRatesForExplicitFocusedLayers) { auto refreshRateConfigs = std::make_unique(m60_90Device, /*currentConfigId=*/HWC_CONFIG_ID_90); @@ -1194,30 +1199,55 @@ TEST_F(RefreshRateConfigsTest, lr.vote = LayerVoteType::ExplicitExactOrMultiple; lr.desiredRefreshRate = 60.0f; lr.name = "60Hz ExplicitExactOrMultiple"; + lr.focused = false; + EXPECT_EQ(mExpected90Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + + lr.focused = true; EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); lr.vote = LayerVoteType::ExplicitDefault; lr.desiredRefreshRate = 60.0f; lr.name = "60Hz ExplicitDefault"; + lr.focused = false; + EXPECT_EQ(mExpected90Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + + lr.focused = true; EXPECT_EQ(mExpected60Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); lr.vote = LayerVoteType::Heuristic; lr.desiredRefreshRate = 60.0f; lr.name = "60Hz Heuristic"; + lr.focused = false; + EXPECT_EQ(mExpected90Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + + lr.focused = true; EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); lr.vote = LayerVoteType::Max; lr.desiredRefreshRate = 60.0f; lr.name = "60Hz Max"; + lr.focused = false; + EXPECT_EQ(mExpected90Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + + lr.focused = true; EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); lr.vote = LayerVoteType::Min; lr.desiredRefreshRate = 60.0f; lr.name = "60Hz Min"; + lr.focused = false; + EXPECT_EQ(mExpected90Config, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); + + lr.focused = true; EXPECT_EQ(mExpected90Config, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})); } @@ -1256,10 +1286,11 @@ TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) { // Return the config ID from calling getBestRefreshRate() for a single layer with the // given voteType and fps. - auto getFrameRate = [&](LayerVoteType voteType, float fps, - bool touchActive = false) -> HwcConfigIndexType { + auto getFrameRate = [&](LayerVoteType voteType, float fps, bool touchActive = false, + bool focused = true) -> HwcConfigIndexType { layers[0].vote = voteType; layers[0].desiredRefreshRate = fps; + layers[0].focused = focused; return refreshRateConfigs->getBestRefreshRate(layers, {.touch = touchActive, .idle = false}) .getConfigId(); }; @@ -1277,6 +1308,14 @@ TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) { EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f)); EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f)); + // Layers not focused are not allowed to override primary config + EXPECT_EQ(HWC_CONFIG_ID_60, + getFrameRate(LayerVoteType::ExplicitDefault, 90.f, /*touch=*/false, + /*focused=*/false)); + EXPECT_EQ(HWC_CONFIG_ID_60, + getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f, /*touch=*/false, + /*focused=*/false)); + // Touch boost should be restricted to the primary range. EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f, /*touch=*/true)); // When we're higher than the primary range max due to a layer frame rate setting, touch boost -- cgit v1.2.3-59-g8ed1b