Add shouldBeSeamless to setFrameRate
This CL adds a new parameter shouldBeSeamless to the existing
setFrameRate APIs. This parameter indicates whether the desired
refresh rate should be achieved only seamlessly or also switches
with visual interruptions for the user are allowed. The default
value of the new parameter is "true".
Test: atest RefreshRateConfigsTest
Test: atest SetFrameRateTest
Test: atest libsurfaceflinger_unittest
Test: atest libgui_test
Bug: 161776961
Change-Id: I0df16e09f77c8c198fd3733fb581a2aaadfed685
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index da71dad..b87c734 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -123,7 +123,7 @@
}
virtual void fillBufferQueueLayerColor(const sp<SurfaceControl>& layer, const Color& color,
- int32_t bufferWidth, int32_t bufferHeight) {
+ uint32_t bufferWidth, uint32_t bufferHeight) {
ANativeWindow_Buffer buffer;
ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
TransactionUtils::fillANativeWindowBufferColor(buffer,
@@ -145,7 +145,7 @@
}
void fillLayerColor(uint32_t mLayerType, const sp<SurfaceControl>& layer, const Color& color,
- int32_t bufferWidth, int32_t bufferHeight) {
+ uint32_t bufferWidth, uint32_t bufferHeight) {
switch (mLayerType) {
case ISurfaceComposerClient::eFXSurfaceBufferQueue:
fillBufferQueueLayerColor(layer, color, bufferWidth, bufferHeight);
diff --git a/services/surfaceflinger/tests/SetFrameRate_test.cpp b/services/surfaceflinger/tests/SetFrameRate_test.cpp
index 02ba9e2..d1bed0c 100644
--- a/services/surfaceflinger/tests/SetFrameRate_test.cpp
+++ b/services/surfaceflinger/tests/SetFrameRate_test.cpp
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
#include <system/window.h>
#include <thread>
@@ -50,8 +46,8 @@
}
}
- const int mLayerWidth = 32;
- const int mLayerHeight = 32;
+ const uint32_t mLayerWidth = 32;
+ const uint32_t mLayerHeight = 32;
sp<SurfaceControl> mLayer;
uint32_t mLayerType;
};
@@ -59,26 +55,27 @@
TEST_F(SetFrameRateTest, BufferQueueLayerSetFrameRate) {
CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferQueue);
native_window_set_frame_rate(mLayer->getSurface().get(), 100.f,
- ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT);
+ ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+ /* shouldBeSeamless */ true);
ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
Transaction()
- .setFrameRate(mLayer, 200.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT)
+ .setFrameRate(mLayer, 200.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+ /* shouldBeSeamless */ true)
.apply();
ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
native_window_set_frame_rate(mLayer->getSurface().get(), 300.f,
- ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT);
+ ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+ /* shouldBeSeamless */ true);
ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
}
TEST_F(SetFrameRateTest, BufferStateLayerSetFrameRate) {
CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferState);
Transaction()
- .setFrameRate(mLayer, 400.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT)
+ .setFrameRate(mLayer, 400.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+ /* shouldBeSeamless */ true)
.apply();
ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::GREEN));
}
} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index 01badf4..a361b1e 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -98,14 +98,14 @@
outTransformHint, format);
}
- void fillLayerColor(const sp<SurfaceControl>& layer, const Color& color, int32_t bufferWidth,
- int32_t bufferHeight) {
+ void fillLayerColor(const sp<SurfaceControl>& layer, const Color& color, uint32_t bufferWidth,
+ uint32_t bufferHeight) {
ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerColor(mLayerType, layer, color,
bufferWidth, bufferHeight));
}
- void fillLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
- int32_t bufferHeight, const Color& topLeft, const Color& topRight,
+ void fillLayerQuadrant(const sp<SurfaceControl>& layer, uint32_t bufferWidth,
+ uint32_t bufferHeight, const Color& topLeft, const Color& topRight,
const Color& bottomLeft, const Color& bottomRight) {
ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerQuadrant(mLayerType, layer,
bufferWidth, bufferHeight,
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
index cb376cd..3b50321 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -78,7 +78,7 @@
for (auto& [weak, info] : history().mLayerInfos) {
if (auto strong = weak.promote(); strong && strong.get() == layer) {
info->setDefaultLayerVote(vote);
- info->setLayerVote(vote, 0);
+ info->setLayerVote({vote, 0, false});
return;
}
}
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 4762fd4..df76110 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -57,6 +57,8 @@
static inline const HwcConfigIndexType HWC_CONFIG_ID_72 = HwcConfigIndexType(2);
static inline const HwcConfigIndexType HWC_CONFIG_ID_120 = HwcConfigIndexType(3);
static inline const HwcConfigIndexType HWC_CONFIG_ID_30 = HwcConfigIndexType(4);
+ static inline const HwcConfigIndexType HWC_CONFIG_ID_25 = HwcConfigIndexType(5);
+ static inline const HwcConfigIndexType HWC_CONFIG_ID_50 = HwcConfigIndexType(6);
// Test configs
std::shared_ptr<const HWC2::Display::Config> mConfig60 =
@@ -77,8 +79,16 @@
createConfig(HWC_CONFIG_ID_120, 1, static_cast<int64_t>(1e9f / 120));
std::shared_ptr<const HWC2::Display::Config> mConfig30 =
createConfig(HWC_CONFIG_ID_30, 0, static_cast<int64_t>(1e9f / 30));
+ std::shared_ptr<const HWC2::Display::Config> mConfig30DifferentGroup =
+ createConfig(HWC_CONFIG_ID_30, 1, static_cast<int64_t>(1e9f / 30));
+ std::shared_ptr<const HWC2::Display::Config> mConfig25DifferentGroup =
+ createConfig(HWC_CONFIG_ID_25, 1, static_cast<int64_t>(1e9f / 25));
+ std::shared_ptr<const HWC2::Display::Config> mConfig50 =
+ createConfig(HWC_CONFIG_ID_50, 0, static_cast<int64_t>(1e9f / 50));
// Test device configurations
+ // The positions of the configs in the arrays below MUST match their IDs. For example,
+ // the first config should always be 60Hz, the second 90Hz etc.
std::vector<std::shared_ptr<const HWC2::Display::Config>> m60OnlyConfigDevice = {mConfig60};
std::vector<std::shared_ptr<const HWC2::Display::Config>> m60_90Device = {mConfig60, mConfig90};
std::vector<std::shared_ptr<const HWC2::Display::Config>> m60_90DeviceWithDifferentGroups =
@@ -104,6 +114,14 @@
{mConfig60, mConfig90, mConfig72, mConfig120DifferentGroup, mConfig30};
std::vector<std::shared_ptr<const HWC2::Display::Config>> m30_60_90Device =
{mConfig60, mConfig90, mConfig72DifferentGroup, mConfig120DifferentGroup, mConfig30};
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> m25_30_50_60Device =
+ {mConfig60,
+ mConfig90,
+ mConfig72DifferentGroup,
+ mConfig120DifferentGroup,
+ mConfig30DifferentGroup,
+ mConfig25DifferentGroup,
+ mConfig50};
// Expected RefreshRate objects
RefreshRate mExpected60Config = {HWC_CONFIG_ID_60, mConfig60, "60fps", 60,
@@ -292,8 +310,8 @@
/*currentConfigId=*/HWC_CONFIG_ID_60);
const auto makeLayerRequirements = [](float refreshRate) -> std::vector<LayerRequirement> {
- return {{"testLayer", LayerVoteType::Heuristic, refreshRate, /*weight*/ 1.0f,
- /*focused*/ false}};
+ return {{"testLayer", LayerVoteType::Heuristic, refreshRate, /*shouldBeSeamless*/ true,
+ /*weight*/ 1.0f, /*focused*/ false}};
};
EXPECT_EQ(mExpected90Config,
@@ -1245,7 +1263,9 @@
auto& layer = layers[0];
layer.vote = LayerVoteType::ExplicitDefault;
layer.desiredRefreshRate = 90.0f;
+ layer.shouldBeSeamless = false;
layer.name = "90Hz ExplicitDefault";
+ layer.focused = true;
ASSERT_EQ(HWC_CONFIG_ID_60,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
@@ -1258,6 +1278,104 @@
ASSERT_EQ(HWC_CONFIG_ID_90,
refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
.getConfigId());
+
+ // Verify that we won't change the group if seamless switch is required.
+ layer.shouldBeSeamless = true;
+ ASSERT_EQ(HWC_CONFIG_ID_60,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getConfigId());
+
+ // At this point the default config in the DisplayManager policy with be 60Hz.
+ // Verify that if the current config is in another group and there are no layers with
+ // shouldBeSeamless=false we'll go back to the default group.
+ refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+ layer.desiredRefreshRate = 60.0f;
+ layer.name = "60Hz ExplicitDefault";
+ layer.shouldBeSeamless = true;
+ ASSERT_EQ(HWC_CONFIG_ID_60,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getConfigId());
+
+ // If there's a layer with shouldBeSeamless=false, another layer with shouldBeSeamless=true
+ // can't change the config group.
+ refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+ auto layer2 = LayerRequirement{.weight = 0.5f};
+ layer2.vote = LayerVoteType::ExplicitDefault;
+ layer2.desiredRefreshRate = 90.0f;
+ layer2.name = "90Hz ExplicitDefault";
+ layer2.shouldBeSeamless = false;
+ layer2.focused = false;
+ layers.push_back(layer2);
+ ASSERT_EQ(HWC_CONFIG_ID_90,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getConfigId());
+}
+
+TEST_F(RefreshRateConfigsTest, nonSeamlessVotePrefersSeamlessSwitches) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m30_60Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ // Allow group switching.
+ RefreshRateConfigs::Policy policy;
+ policy.defaultConfig = refreshRateConfigs->getCurrentPolicy().defaultConfig;
+ policy.allowGroupSwitching = true;
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& layer = layers[0];
+ layer.vote = LayerVoteType::ExplicitExactOrMultiple;
+ layer.desiredRefreshRate = 60.0f;
+ layer.shouldBeSeamless = false;
+ layer.name = "60Hz ExplicitExactOrMultiple";
+ layer.focused = true;
+
+ ASSERT_EQ(HWC_CONFIG_ID_60,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getConfigId());
+
+ refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_120);
+ ASSERT_EQ(HWC_CONFIG_ID_120,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getConfigId());
+}
+
+TEST_F(RefreshRateConfigsTest, nonSeamlessExactAndSeamlessMultipleLayers) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m25_30_50_60Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ // Allow group switching.
+ RefreshRateConfigs::Policy policy;
+ policy.defaultConfig = refreshRateConfigs->getCurrentPolicy().defaultConfig;
+ policy.allowGroupSwitching = true;
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
+
+ auto layers = std::vector<
+ LayerRequirement>{LayerRequirement{.name = "60Hz ExplicitDefault",
+ .vote = LayerVoteType::ExplicitDefault,
+ .desiredRefreshRate = 60.0f,
+ .shouldBeSeamless = false,
+ .weight = 0.5f,
+ .focused = false},
+ LayerRequirement{.name = "25Hz ExplicitExactOrMultiple",
+ .vote = LayerVoteType::ExplicitExactOrMultiple,
+ .desiredRefreshRate = 25.0f,
+ .shouldBeSeamless = true,
+ .weight = 1.0f,
+ .focused = true}};
+ auto& seamedLayer = layers[0];
+
+ ASSERT_EQ(HWC_CONFIG_ID_50,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getConfigId());
+
+ seamedLayer.name = "30Hz ExplicitDefault", seamedLayer.desiredRefreshRate = 30.0f;
+ refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_30);
+
+ ASSERT_EQ(HWC_CONFIG_ID_25,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getConfigId());
}
TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) {
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index de66f8f..d0bb9e2 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -108,7 +108,7 @@
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
- EXPECT_EQ(0u, times.count("90fps"));
+ EXPECT_EQ(0u, times.count("90.00fps"));
mRefreshRateStats->setConfigMode(CONFIG_ID_0);
mRefreshRateStats->setPowerMode(PowerMode::ON);
@@ -116,15 +116,15 @@
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
EXPECT_EQ(screenOff, times["ScreenOff"]);
- ASSERT_EQ(1u, times.count("90fps"));
- EXPECT_LT(0, times["90fps"]);
+ ASSERT_EQ(1u, times.count("90.00fps"));
+ EXPECT_LT(0, times["90.00fps"]);
mRefreshRateStats->setPowerMode(PowerMode::DOZE);
- int ninety = mRefreshRateStats->getTotalTimes()["90fps"];
+ int ninety = mRefreshRateStats->getTotalTimes()["90.00fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
- EXPECT_EQ(ninety, times["90fps"]);
+ EXPECT_EQ(ninety, times["90.00fps"]);
mRefreshRateStats->setConfigMode(CONFIG_ID_0);
screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
@@ -133,7 +133,7 @@
// Because the power mode is not PowerMode::ON, switching the config
// does not update refresh rates that come from the config.
EXPECT_LT(screenOff, times["ScreenOff"]);
- EXPECT_EQ(ninety, times["90fps"]);
+ EXPECT_EQ(ninety, times["90.00fps"]);
}
TEST_F(RefreshRateStatsTest, twoConfigsTest) {
@@ -163,53 +163,53 @@
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
EXPECT_EQ(screenOff, times["ScreenOff"]);
- ASSERT_EQ(1u, times.count("90fps"));
- EXPECT_LT(0, times["90fps"]);
+ ASSERT_EQ(1u, times.count("90.00fps"));
+ EXPECT_LT(0, times["90.00fps"]);
// When power mode is normal, time for configs updates.
mRefreshRateStats->setConfigMode(CONFIG_ID_1);
- int ninety = mRefreshRateStats->getTotalTimes()["90fps"];
+ int ninety = mRefreshRateStats->getTotalTimes()["90.00fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
EXPECT_EQ(screenOff, times["ScreenOff"]);
- EXPECT_EQ(ninety, times["90fps"]);
- ASSERT_EQ(1u, times.count("60fps"));
- EXPECT_LT(0, times["60fps"]);
+ EXPECT_EQ(ninety, times["90.00fps"]);
+ ASSERT_EQ(1u, times.count("60.00fps"));
+ EXPECT_LT(0, times["60.00fps"]);
mRefreshRateStats->setConfigMode(CONFIG_ID_0);
- int sixty = mRefreshRateStats->getTotalTimes()["60fps"];
+ int sixty = mRefreshRateStats->getTotalTimes()["60.00fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
EXPECT_EQ(screenOff, times["ScreenOff"]);
- EXPECT_LT(ninety, times["90fps"]);
- EXPECT_EQ(sixty, times["60fps"]);
+ EXPECT_LT(ninety, times["90.00fps"]);
+ EXPECT_EQ(sixty, times["60.00fps"]);
mRefreshRateStats->setConfigMode(CONFIG_ID_1);
- ninety = mRefreshRateStats->getTotalTimes()["90fps"];
+ ninety = mRefreshRateStats->getTotalTimes()["90.00fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
EXPECT_EQ(screenOff, times["ScreenOff"]);
- EXPECT_EQ(ninety, times["90fps"]);
- EXPECT_LT(sixty, times["60fps"]);
+ EXPECT_EQ(ninety, times["90.00fps"]);
+ EXPECT_LT(sixty, times["60.00fps"]);
// Because the power mode is not PowerMode::ON, switching the config
// does not update refresh rates that come from the config.
mRefreshRateStats->setPowerMode(PowerMode::DOZE);
mRefreshRateStats->setConfigMode(CONFIG_ID_0);
- sixty = mRefreshRateStats->getTotalTimes()["60fps"];
+ sixty = mRefreshRateStats->getTotalTimes()["60.00fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
- EXPECT_EQ(ninety, times["90fps"]);
- EXPECT_EQ(sixty, times["60fps"]);
+ EXPECT_EQ(ninety, times["90.00fps"]);
+ EXPECT_EQ(sixty, times["60.00fps"]);
mRefreshRateStats->setConfigMode(CONFIG_ID_1);
screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
- EXPECT_EQ(ninety, times["90fps"]);
- EXPECT_EQ(sixty, times["60fps"]);
+ EXPECT_EQ(ninety, times["90.00fps"]);
+ EXPECT_EQ(sixty, times["60.00fps"]);
}
} // namespace
} // namespace scheduler