Refactor game-related frame rate override to LayerHistory
Previously game-related frame rate overrides are maintained in Scheduler
only, which does not provide votes to the actual display refresh rate.
This causes an issue that these overrides will only be viable when they
are the divisors of the display refresh rate at the moment.
This change moves the game intervention and newly-added game default
frame rate overrides to LayerHistory, where overrides will be considered
in layer frame rate votes. Scheduler will get this information and
select the display frame rate accordingly
Bug: 286084594
Test: SurfaceFlinger unit test
atest LayerHistoryTest
atest FrameRateOverrideMappingsTest
atest CtsGraphicsTestCases --test-filter "SetFrameRateTest*"
atest CtsFrameRateOverrideTestCases
Change-Id: I9957af8e53fbdd44b8d70028572e6db8e779a1fe
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 5888a55..5449aeb 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -55,7 +55,6 @@
"ReleaseBufferCallback_test.cpp",
"ScreenCapture_test.cpp",
"SetFrameRate_test.cpp",
- "SetFrameRateOverride_test.cpp",
"SetGeometry_test.cpp",
"Stress_test.cpp",
"TextureFiltering_test.cpp",
diff --git a/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp b/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp
deleted file mode 100644
index e43ef95..0000000
--- a/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android/gui/ISurfaceComposer.h>
-#include <gtest/gtest.h>
-#include <gui/DisplayEventReceiver.h>
-#include <gui/SurfaceComposerClient.h>
-#include <sys/epoll.h>
-#include <algorithm>
-
-namespace android {
-namespace {
-using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
-using gui::ISurfaceComposer;
-
-class SetFrameRateOverrideTest : public ::testing::Test {
-protected:
- void SetUp() override {
- const ISurfaceComposer::VsyncSource vsyncSource =
- ISurfaceComposer::VsyncSource::eVsyncSourceApp;
- const EventRegistrationFlags eventRegistration = {
- ISurfaceComposer::EventRegistration::frameRateOverride};
-
- mDisplayEventReceiver =
- std::make_unique<DisplayEventReceiver>(vsyncSource, eventRegistration);
- EXPECT_EQ(NO_ERROR, mDisplayEventReceiver->initCheck());
-
- mEpollFd = epoll_create1(EPOLL_CLOEXEC);
- EXPECT_GT(mEpollFd, 1);
-
- epoll_event event;
- event.events = EPOLLIN;
- EXPECT_EQ(0, epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mDisplayEventReceiver->getFd(), &event));
- }
-
- void TearDown() override { close(mEpollFd); }
-
- void setFrameRateAndListenEvents(uid_t uid, float frameRate) {
- status_t ret = SurfaceComposerClient::setOverrideFrameRate(uid, frameRate);
- ASSERT_EQ(NO_ERROR, ret);
-
- DisplayEventReceiver::Event event;
- bool isOverrideFlushReceived = false;
- mFrameRateOverrides.clear();
-
- epoll_event epollEvent;
- while (epoll_wait(mEpollFd, &epollEvent, 1, 1000) > 0) {
- while (mDisplayEventReceiver->getEvents(&event, 1) > 0) {
- if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE) {
- mFrameRateOverrides.emplace_back(event.frameRateOverride);
- }
- if (event.header.type ==
- DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH) {
- isOverrideFlushReceived = true;
- }
- }
-
- if (isOverrideFlushReceived) break;
- }
- }
-
- std::unique_ptr<DisplayEventReceiver> mDisplayEventReceiver;
- std::vector<FrameRateOverride> mFrameRateOverrides;
-
- int mEpollFd;
-};
-
-TEST_F(SetFrameRateOverrideTest, SetFrameRateOverrideCall) {
- uid_t uid = getuid();
- float frameRate = 30.0f;
- setFrameRateAndListenEvents(uid, frameRate);
- // check if the frame rate override we set exists
- ASSERT_TRUE(std::find_if(mFrameRateOverrides.begin(), mFrameRateOverrides.end(),
- [uid = uid, frameRate = frameRate](auto i) {
- return uid == i.uid && frameRate == i.frameRateHz;
- }) != mFrameRateOverrides.end());
-
- // test removing frame rate override
- frameRate = 0.0f;
- setFrameRateAndListenEvents(uid, frameRate);
- ASSERT_TRUE(std::find_if(mFrameRateOverrides.begin(), mFrameRateOverrides.end(),
- [uid = uid, frameRate = frameRate](auto i) {
- return uid == i.uid && frameRate == i.frameRateHz;
- }) == mFrameRateOverrides.end());
-}
-} // namespace
-} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp b/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp
index a581c7a..7c1d4b4 100644
--- a/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp
@@ -17,6 +17,8 @@
#undef LOG_TAG
#define LOG_TAG "FrameRateOverrideMappingsTest"
+#include <com_android_graphics_surfaceflinger_flags.h>
+#include <common/test/FlagUtils.h>
#include <gtest/gtest.h>
#include <unordered_map>
@@ -34,6 +36,8 @@
};
namespace {
+using namespace com::android::graphics::surfaceflinger;
+
TEST_F(FrameRateOverrideMappingsTest, testUpdateFrameRateOverridesByContent) {
mFrameRateOverrideByContent.clear();
mFrameRateOverrideByContent.emplace(0, 30.0_Hz);
@@ -59,6 +63,8 @@
}
TEST_F(FrameRateOverrideMappingsTest, testSetGameModeRefreshRateForUid) {
+ SET_FLAG_FOR_TEST(flags::game_default_frame_rate, false);
+
mFrameRateOverrideMappings.setGameModeRefreshRateForUid({1, 30.0f});
mFrameRateOverrideMappings.setGameModeRefreshRateForUid({2, 90.0f});
@@ -95,6 +101,7 @@
}
TEST_F(FrameRateOverrideMappingsTest, testGetFrameRateOverrideForUidMixed) {
+ SET_FLAG_FOR_TEST(flags::game_default_frame_rate, false);
mFrameRateOverrideByContent.clear();
mFrameRateOverrideByContent.emplace(0, 30.0_Hz);
mFrameRateOverrideByContent.emplace(1, 60.0_Hz);
@@ -111,7 +118,6 @@
ASSERT_EQ(allFrameRateOverrides,
mFrameRateOverrideMappings.getAllFrameRateOverrides(
/*supportsFrameRateOverrideByContent*/ true));
-
mFrameRateOverrideMappings.setGameModeRefreshRateForUid({1, 30.0f});
mFrameRateOverrideMappings.setGameModeRefreshRateForUid({2, 90.0f});
mFrameRateOverrideMappings.setGameModeRefreshRateForUid({4, 120.0f});
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index b88ef56..0ae3ca3 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -118,6 +118,9 @@
auto createLayer(std::string name) {
return sp<MockLayer>::make(mFlinger.flinger(), std::move(name));
}
+ auto createLayer(std::string name, uint32_t uid) {
+ return sp<MockLayer>::make(mFlinger.flinger(), std::move(name), std::move(uid));
+ }
void recordFramesAndExpect(const sp<MockLayer>& layer, nsecs_t& time, Fps frameRate,
Fps desiredRefreshRate, int numFrames) {
@@ -247,6 +250,105 @@
}
}
+TEST_F(LayerHistoryTest, gameFrameRateOverrideMapping) {
+ SET_FLAG_FOR_TEST(flags::game_default_frame_rate, true);
+
+ history().updateGameDefaultFrameRateOverride(FrameRateOverride({0, 60.0f}));
+
+ auto overridePair = history().getGameFrameRateOverride(0);
+ EXPECT_EQ(0_Hz, overridePair.first);
+ EXPECT_EQ(60_Hz, overridePair.second);
+
+ history().updateGameModeFrameRateOverride(FrameRateOverride({0, 40.0f}));
+ history().updateGameModeFrameRateOverride(FrameRateOverride({1, 120.0f}));
+
+ overridePair = history().getGameFrameRateOverride(0);
+ EXPECT_EQ(40_Hz, overridePair.first);
+ EXPECT_EQ(60_Hz, overridePair.second);
+
+ overridePair = history().getGameFrameRateOverride(1);
+ EXPECT_EQ(120_Hz, overridePair.first);
+ EXPECT_EQ(0_Hz, overridePair.second);
+
+ history().updateGameDefaultFrameRateOverride(FrameRateOverride({0, 0.0f}));
+ history().updateGameModeFrameRateOverride(FrameRateOverride({1, 0.0f}));
+
+ overridePair = history().getGameFrameRateOverride(0);
+ EXPECT_EQ(40_Hz, overridePair.first);
+ EXPECT_EQ(0_Hz, overridePair.second);
+
+ overridePair = history().getGameFrameRateOverride(1);
+ EXPECT_EQ(0_Hz, overridePair.first);
+ EXPECT_EQ(0_Hz, overridePair.second);
+}
+
+TEST_F(LayerHistoryTest, oneLayerGameFrameRateOverride) {
+ SET_FLAG_FOR_TEST(flags::game_default_frame_rate, true);
+
+ const uid_t uid = 0;
+ const Fps gameDefaultFrameRate = Fps::fromValue(30.0f);
+ const Fps gameModeFrameRate = Fps::fromValue(60.0f);
+ const auto layer = createLayer("GameFrameRateLayer", uid);
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+ EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid));
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ // update game default frame rate override
+ history().updateGameDefaultFrameRateOverride(
+ FrameRateOverride({uid, gameDefaultFrameRate.getValue()}));
+
+ nsecs_t time = systemTime();
+ LayerHistory::Summary summary;
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer->getSequence(), layer->getLayerProps(), time, time,
+ LayerHistory::LayerUpdateType::Buffer);
+ time += gameDefaultFrameRate.getPeriodNsecs();
+
+ summary = summarizeLayerHistory(time);
+ }
+
+ ASSERT_EQ(1, summary.size());
+ ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote);
+ ASSERT_EQ(30.0_Hz, summary[0].desiredRefreshRate);
+
+ // test against setFrameRate vote
+ const Fps setFrameRate = Fps::fromValue(120.0f);
+ EXPECT_CALL(*layer, getFrameRateForLayerTree())
+ .WillRepeatedly(
+ Return(Layer::FrameRate(setFrameRate, Layer::FrameRateCompatibility::Default)));
+
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer->getSequence(), layer->getLayerProps(), time, time,
+ LayerHistory::LayerUpdateType::Buffer);
+ time += setFrameRate.getPeriodNsecs();
+
+ summary = summarizeLayerHistory(time);
+ }
+
+ ASSERT_EQ(1, summary.size());
+ ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote);
+ ASSERT_EQ(120.0_Hz, summary[0].desiredRefreshRate);
+
+ // update game mode frame rate override
+ history().updateGameModeFrameRateOverride(
+ FrameRateOverride({uid, gameModeFrameRate.getValue()}));
+
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer->getSequence(), layer->getLayerProps(), time, time,
+ LayerHistory::LayerUpdateType::Buffer);
+ time += gameModeFrameRate.getPeriodNsecs();
+
+ summary = summarizeLayerHistory(time);
+ }
+
+ ASSERT_EQ(1, summary.size());
+ ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote);
+ ASSERT_EQ(60.0_Hz, summary[0].desiredRefreshRate);
+}
+
TEST_F(LayerHistoryTest, oneInvisibleLayer) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index 3dfb649..4204aa0 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -17,6 +17,7 @@
#pragma once
#include <gmock/gmock.h>
+#include <optional>
namespace android::mock {
@@ -27,6 +28,13 @@
EXPECT_CALL(*this, getDefaultFrameRateCompatibility())
.WillOnce(testing::Return(scheduler::FrameRateCompatibility::Default));
}
+
+ MockLayer(SurfaceFlinger* flinger, std::string name, std::optional<uint32_t> uid)
+ : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {}, uid)) {
+ EXPECT_CALL(*this, getDefaultFrameRateCompatibility())
+ .WillOnce(testing::Return(scheduler::FrameRateCompatibility::Default));
+ }
+
explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {}
MOCK_CONST_METHOD0(getType, const char*());