summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Andy Yu <chingtangyu@google.com> 2023-11-03 11:22:46 -0700
committer Andy Yu <chingtangyu@google.com> 2023-12-07 15:30:22 -0800
commit8c2703dfc85c911d28111f5b1e54ee8acb7fcbb2 (patch)
tree6c7477a49b2a721e8ab60c509e281c61bfec36be
parent926dbea7a7abef622dd3d5f73a3e07773450f073 (diff)
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
-rw-r--r--libs/gui/SurfaceComposerClient.cpp11
-rw-r--r--libs/gui/aidl/android/gui/ISurfaceComposer.aidl13
-rw-r--r--libs/gui/fuzzer/libgui_fuzzer_utils.h3
-rw-r--r--libs/gui/include/gui/SurfaceComposerClient.h8
-rw-r--r--libs/gui/tests/Surface_test.cpp6
-rw-r--r--services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp18
-rw-r--r--services/surfaceflinger/Scheduler/LayerHistory.cpp91
-rw-r--r--services/surfaceflinger/Scheduler/LayerHistory.h17
-rw-r--r--services/surfaceflinger/Scheduler/LayerInfo.h3
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.cpp19
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.h12
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp30
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h7
-rw-r--r--services/surfaceflinger/common/FlagManager.cpp2
-rw-r--r--services/surfaceflinger/common/include/common/FlagManager.h1
-rw-r--r--services/surfaceflinger/surfaceflinger_flags.aconfig8
-rw-r--r--services/surfaceflinger/tests/Android.bp1
-rw-r--r--services/surfaceflinger/tests/SetFrameRateOverride_test.cpp100
-rw-r--r--services/surfaceflinger/tests/unittests/FrameRateOverrideMappingsTest.cpp8
-rw-r--r--services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp102
-rw-r--r--services/surfaceflinger/tests/unittests/mock/MockLayer.h8
21 files changed, 338 insertions, 130 deletions
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 922b0ddcde..8b6f2023dc 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -2782,9 +2782,16 @@ status_t SurfaceComposerClient::getHdrOutputConversionSupport(bool* isSupported)
return statusTFromBinderStatus(status);
}
-status_t SurfaceComposerClient::setOverrideFrameRate(uid_t uid, float frameRate) {
+status_t SurfaceComposerClient::setGameModeFrameRateOverride(uid_t uid, float frameRate) {
binder::Status status =
- ComposerServiceAIDL::getComposerService()->setOverrideFrameRate(uid, frameRate);
+ ComposerServiceAIDL::getComposerService()->setGameModeFrameRateOverride(uid, frameRate);
+ return statusTFromBinderStatus(status);
+}
+
+status_t SurfaceComposerClient::setGameDefaultFrameRateOverride(uid_t uid, float frameRate) {
+ binder::Status status =
+ ComposerServiceAIDL::getComposerService()->setGameDefaultFrameRateOverride(uid,
+ frameRate);
return statusTFromBinderStatus(status);
}
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index d24f8eefd5..e3122bc300 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -477,10 +477,21 @@ interface ISurfaceComposer {
/**
* Set the override frame rate for a specified uid by GameManagerService.
+ * This override is controlled by game mode interventions.
+ * Passing the frame rate and uid to SurfaceFlinger to update the override mapping
+ * in the LayerHistory.
+ */
+ void setGameModeFrameRateOverride(int uid, float frameRate);
+
+ /**
+ * Set the override frame rate for a specified uid by GameManagerService.
+ * This override is controlled by game default frame rate sysprop:
+ * "ro.surface_flinger.game_default_frame_rate_override" holding the override value,
+ * "persisit.graphics.game_default_frame_rate.enabled" to determine if it's enabled.
* Passing the frame rate and uid to SurfaceFlinger to update the override mapping
* in the scheduler.
*/
- void setOverrideFrameRate(int uid, float frameRate);
+ void setGameDefaultFrameRateOverride(int uid, float frameRate);
oneway void updateSmallAreaDetection(in int[] appIds, in float[] thresholds);
diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h
index ffe7e4123b..9933680c4b 100644
--- a/libs/gui/fuzzer/libgui_fuzzer_utils.h
+++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h
@@ -149,7 +149,8 @@ public:
(const gui::Color&, const gui::Color&, float, float, float), (override));
MOCK_METHOD(binder::Status, getDisplayDecorationSupport,
(const sp<IBinder>&, std::optional<gui::DisplayDecorationSupport>*), (override));
- MOCK_METHOD(binder::Status, setOverrideFrameRate, (int32_t, float), (override));
+ MOCK_METHOD(binder::Status, setGameModeFrameRateOverride, (int32_t, float), (override));
+ MOCK_METHOD(binder::Status, setGameDefaultFrameRateOverride, (int32_t, float), (override));
MOCK_METHOD(binder::Status, enableRefreshRateOverlay, (bool), (override));
MOCK_METHOD(binder::Status, setDebugFlash, (int), (override));
MOCK_METHOD(binder::Status, scheduleComposite, (), (override));
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 5bf6c473d9..14e3dd583e 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -201,7 +201,13 @@ public:
// Sets the frame rate of a particular app (uid). This is currently called
// by GameManager.
- static status_t setOverrideFrameRate(uid_t uid, float frameRate);
+ static status_t setGameModeFrameRateOverride(uid_t uid, float frameRate);
+
+ // Sets the frame rate of a particular app (uid). This is currently called
+ // by GameManager and controlled by two sysprops:
+ // "ro.surface_flinger.game_default_frame_rate_override" holding the override value,
+ // "persisit.graphics.game_default_frame_rate.enabled" to determine if it's enabled.
+ static status_t setGameDefaultFrameRateOverride(uid_t uid, float frameRate);
// Update the small area detection whole appId-threshold mappings by same size appId and
// threshold vector.
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 60221aa30a..c6ea317949 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -921,7 +921,11 @@ public:
return binder::Status::ok();
}
- binder::Status setOverrideFrameRate(int32_t /*uid*/, float /*frameRate*/) override {
+ binder::Status setGameModeFrameRateOverride(int32_t /*uid*/, float /*frameRate*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setGameDefaultFrameRateOverride(int32_t /*uid*/, float /*frameRate*/) override {
return binder::Status::ok();
}
diff --git a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp
index cb9bfe93db..82af61a032 100644
--- a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp
+++ b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp
@@ -15,6 +15,7 @@
*/
#include "FrameRateOverrideMappings.h"
+#include <common/FlagManager.h>
namespace android::scheduler {
using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
@@ -30,7 +31,7 @@ std::optional<Fps> FrameRateOverrideMappings::getFrameRateOverrideForUid(
}
}
- {
+ if (!FlagManager::getInstance().game_default_frame_rate()) {
const auto iter = mFrameRateOverridesFromGameManager.find(uid);
if (iter != mFrameRateOverridesFromGameManager.end()) {
return iter->second;
@@ -61,10 +62,13 @@ std::vector<FrameRateOverride> FrameRateOverrideMappings::getAllFrameRateOverrid
for (const auto& [uid, frameRate] : mFrameRateOverridesFromBackdoor) {
overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()});
}
- for (const auto& [uid, frameRate] : mFrameRateOverridesFromGameManager) {
- if (std::find_if(overrides.begin(), overrides.end(),
- [uid = uid](auto i) { return i.uid == uid; }) == overrides.end()) {
- overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()});
+
+ if (!FlagManager::getInstance().game_default_frame_rate()) {
+ for (const auto& [uid, frameRate] : mFrameRateOverridesFromGameManager) {
+ if (std::find_if(overrides.begin(), overrides.end(),
+ [uid = uid](auto i) { return i.uid == uid; }) == overrides.end()) {
+ overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()});
+ }
}
}
@@ -93,7 +97,9 @@ void FrameRateOverrideMappings::dump(utils::Dumper& dumper) const {
if (!hasOverrides) return;
dump(dumper, "setFrameRate"sv, mFrameRateOverridesByContent);
- dump(dumper, "GameManager"sv, mFrameRateOverridesFromGameManager);
+ if (!FlagManager::getInstance().game_default_frame_rate()) {
+ dump(dumper, "GameManager"sv, mFrameRateOverridesFromGameManager);
+ }
dump(dumper, "Backdoor"sv, mFrameRateOverridesFromBackdoor);
}
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 9c003026ea..5ce883ce39 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -266,6 +266,7 @@ void LayerHistory::partitionLayers(nsecs_t now) {
if (isLayerActive(*info, threshold)) {
// Set layer vote if set
const auto frameRate = info->getSetFrameRateVote();
+
const auto voteType = [&]() {
switch (frameRate.vote.type) {
case Layer::FrameRateCompatibility::Default:
@@ -283,12 +284,40 @@ void LayerHistory::partitionLayers(nsecs_t now) {
}
}();
- if (frameRate.isValid()) {
- const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote;
- info->setLayerVote({type, frameRate.vote.rate, frameRate.vote.seamlessness,
- frameRate.category});
+ if (FlagManager::getInstance().game_default_frame_rate()) {
+ // Determine the layer frame rate considering the following priorities:
+ // 1. Game mode intervention frame rate override
+ // 2. setFrameRate vote
+ // 3. Game default frame rate override
+
+ const auto& [gameModeFrameRateOverride, gameDefaultFrameRateOverride] =
+ getGameFrameRateOverrideLocked(info->getOwnerUid());
+
+ const auto gameFrameRateOverrideVoteType =
+ info->isVisible() ? LayerVoteType::ExplicitDefault : LayerVoteType::NoVote;
+
+ const auto setFrameRateVoteType =
+ info->isVisible() ? voteType : LayerVoteType::NoVote;
+
+ if (gameModeFrameRateOverride.isValid()) {
+ info->setLayerVote({gameFrameRateOverrideVoteType, gameModeFrameRateOverride});
+ } else if (frameRate.isValid()) {
+ info->setLayerVote({setFrameRateVoteType, frameRate.vote.rate,
+ frameRate.vote.seamlessness, frameRate.category});
+ } else if (gameDefaultFrameRateOverride.isValid()) {
+ info->setLayerVote(
+ {gameFrameRateOverrideVoteType, gameDefaultFrameRateOverride});
+ } else {
+ info->resetLayerVote();
+ }
} else {
- info->resetLayerVote();
+ if (frameRate.isValid()) {
+ const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote;
+ info->setLayerVote({type, frameRate.vote.rate, frameRate.vote.seamlessness,
+ frameRate.category});
+ } else {
+ info->resetLayerVote();
+ }
}
it++;
@@ -347,4 +376,56 @@ bool LayerHistory::isSmallDirtyArea(uint32_t dirtyArea, float threshold) const {
return isSmallDirty;
}
+void LayerHistory::updateGameModeFrameRateOverride(FrameRateOverride frameRateOverride) {
+ const uid_t uid = frameRateOverride.uid;
+ std::lock_guard lock(mLock);
+ if (frameRateOverride.frameRateHz != 0.f) {
+ mGameFrameRateOverride[uid].first = Fps::fromValue(frameRateOverride.frameRateHz);
+ } else {
+ if (mGameFrameRateOverride[uid].second.getValue() == 0.f) {
+ mGameFrameRateOverride.erase(uid);
+ } else {
+ mGameFrameRateOverride[uid].first = Fps();
+ }
+ }
+}
+
+void LayerHistory::updateGameDefaultFrameRateOverride(FrameRateOverride frameRateOverride) {
+ const uid_t uid = frameRateOverride.uid;
+ std::lock_guard lock(mLock);
+ if (frameRateOverride.frameRateHz != 0.f) {
+ mGameFrameRateOverride[uid].second = Fps::fromValue(frameRateOverride.frameRateHz);
+ } else {
+ if (mGameFrameRateOverride[uid].first.getValue() == 0.f) {
+ mGameFrameRateOverride.erase(uid);
+ } else {
+ mGameFrameRateOverride[uid].second = Fps();
+ }
+ }
+}
+
+std::pair<Fps, Fps> LayerHistory::getGameFrameRateOverride(uid_t uid) const {
+ if (!FlagManager::getInstance().game_default_frame_rate()) {
+ return std::pair<Fps, Fps>();
+ }
+
+ std::lock_guard lock(mLock);
+
+ return getGameFrameRateOverrideLocked(uid);
+}
+
+std::pair<Fps, Fps> LayerHistory::getGameFrameRateOverrideLocked(uid_t uid) const {
+ if (!FlagManager::getInstance().game_default_frame_rate()) {
+ return std::pair<Fps, Fps>();
+ }
+
+ const auto it = mGameFrameRateOverride.find(uid);
+
+ if (it == mGameFrameRateOverride.end()) {
+ return std::pair<Fps, Fps>(Fps(), Fps());
+ }
+
+ return it->second;
+}
+
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 5a9445bcaf..930d06c8f0 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -43,6 +43,7 @@ struct LayerProps;
class LayerHistory {
public:
+ using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride;
using LayerVoteType = RefreshRateSelector::LayerVoteType;
static constexpr std::chrono::nanoseconds kMaxPeriodForHistory = 1s;
@@ -89,6 +90,15 @@ public:
bool isSmallDirtyArea(uint32_t dirtyArea, float threshold) const;
+ // Updates the frame rate override set by game mode intervention
+ void updateGameModeFrameRateOverride(FrameRateOverride frameRateOverride) EXCLUDES(mLock);
+
+ // Updates the frame rate override set by game default frame rate
+ void updateGameDefaultFrameRateOverride(FrameRateOverride frameRateOverride) EXCLUDES(mLock);
+
+ std::pair<Fps, Fps> getGameFrameRateOverride(uid_t uid) const EXCLUDES(mLock);
+ std::pair<Fps, Fps> getGameFrameRateOverrideLocked(uid_t uid) const REQUIRES(mLock);
+
private:
friend class LayerHistoryTest;
friend class LayerHistoryIntegrationTest;
@@ -137,6 +147,13 @@ private:
// Whether a mode change is in progress or not
std::atomic<bool> mModeChangePending = false;
+
+ // A list to look up the game frame rate overrides
+ // Each entry includes:
+ // 1. the uid of the app
+ // 2. a pair of game mode intervention frame frame and game default frame rate override
+ // set to 0.0 if there is no such override
+ std::map<uid_t, std::pair<Fps, Fps>> mGameFrameRateOverride GUARDED_BY(mLock);
};
} // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 50bb83dc29..326e444815 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -175,7 +175,8 @@ public:
bool pendingModeChange, const LayerProps& props);
// Sets an explicit layer vote. This usually comes directly from the application via
- // ANativeWindow_setFrameRate API
+ // ANativeWindow_setFrameRate API. This is also used by Game Default Frame Rate and
+ // Game Mode Intervention Frame Rate.
void setLayerVote(LayerVote vote) { mLayerVote = vote; }
// Sets the default layer vote. This will be the layer vote after calling to resetLayerVote().
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index aa8d54d69e..6a85788623 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -1226,12 +1226,27 @@ void Scheduler::onActiveDisplayAreaChanged(uint32_t displayArea) {
mLayerHistory.setDisplayArea(displayArea);
}
-void Scheduler::setGameModeRefreshRateForUid(FrameRateOverride frameRateOverride) {
+void Scheduler::setGameModeFrameRateForUid(FrameRateOverride frameRateOverride) {
if (frameRateOverride.frameRateHz > 0.f && frameRateOverride.frameRateHz < 1.f) {
return;
}
- mFrameRateOverrideMappings.setGameModeRefreshRateForUid(frameRateOverride);
+ if (FlagManager::getInstance().game_default_frame_rate()) {
+ // update the frame rate override mapping in LayerHistory
+ mLayerHistory.updateGameModeFrameRateOverride(frameRateOverride);
+ } else {
+ mFrameRateOverrideMappings.setGameModeRefreshRateForUid(frameRateOverride);
+ }
+}
+
+void Scheduler::setGameDefaultFrameRateForUid(FrameRateOverride frameRateOverride) {
+ if (!FlagManager::getInstance().game_default_frame_rate() ||
+ (frameRateOverride.frameRateHz > 0.f && frameRateOverride.frameRateHz < 1.f)) {
+ return;
+ }
+
+ // update the frame rate override mapping in LayerHistory
+ mLayerHistory.updateGameDefaultFrameRateOverride(frameRateOverride);
}
void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverride) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 454ef83632..ce585c624a 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -293,7 +293,17 @@ public:
// FrameRateOverride.refreshRateHz == 0 means no preference.
void setPreferredRefreshRateForUid(FrameRateOverride);
- void setGameModeRefreshRateForUid(FrameRateOverride);
+ // Stores the frame rate override that a game should run at set by game interventions.
+ // FrameRateOverride.refreshRateHz == 0 means no preference.
+ void setGameModeFrameRateForUid(FrameRateOverride) EXCLUDES(mDisplayLock);
+
+ // Stores the frame rate override that a game should run rat set by default game frame rate.
+ // FrameRateOverride.refreshRateHz == 0 means no preference, game default game frame rate is not
+ // enabled.
+ //
+ // "ro.surface_flinger.game_default_frame_rate_override" sets the frame rate value,
+ // "persist.graphics.game_default_frame_rate.enabled" controls whether this feature is enabled.
+ void setGameDefaultFrameRateForUid(FrameRateOverride) EXCLUDES(mDisplayLock);
void updateSmallAreaDetection(std::vector<std::pair<int32_t, float>>& uidThresholdMappings);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c4de02fce9..8f26d16d45 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -8440,17 +8440,25 @@ const std::unordered_map<std::string, uint32_t>& SurfaceFlinger::getGenericLayer
return genericLayerMetadataKeyMap;
}
-status_t SurfaceFlinger::setOverrideFrameRate(uid_t uid, float frameRate) {
+status_t SurfaceFlinger::setGameModeFrameRateOverride(uid_t uid, float frameRate) {
PhysicalDisplayId displayId = [&]() {
Mutex::Autolock lock(mStateLock);
return getDefaultDisplayDeviceLocked()->getPhysicalId();
}();
- mScheduler->setGameModeRefreshRateForUid(FrameRateOverride{static_cast<uid_t>(uid), frameRate});
+ mScheduler->setGameModeFrameRateForUid(FrameRateOverride{static_cast<uid_t>(uid), frameRate});
mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId);
return NO_ERROR;
}
+status_t SurfaceFlinger::setGameDefaultFrameRateOverride(uid_t uid, float frameRate) {
+ if (FlagManager::getInstance().game_default_frame_rate()) {
+ mScheduler->setGameDefaultFrameRateForUid(
+ FrameRateOverride{static_cast<uid_t>(uid), frameRate});
+ }
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::updateSmallAreaDetection(
std::vector<std::pair<int32_t, float>>& appIdThresholdMappings) {
mScheduler->updateSmallAreaDetection(appIdThresholdMappings);
@@ -9800,13 +9808,25 @@ binder::Status SurfaceComposerAIDL::getDisplayDecorationSupport(
return binder::Status::ok();
}
-binder::Status SurfaceComposerAIDL::setOverrideFrameRate(int32_t uid, float frameRate) {
+binder::Status SurfaceComposerAIDL::setGameModeFrameRateOverride(int32_t uid, float frameRate) {
+ status_t status;
+ const int c_uid = IPCThreadState::self()->getCallingUid();
+ if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) {
+ status = mFlinger->setGameModeFrameRateOverride(uid, frameRate);
+ } else {
+ ALOGE("setGameModeFrameRateOverride() permission denied for uid: %d", c_uid);
+ status = PERMISSION_DENIED;
+ }
+ return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setGameDefaultFrameRateOverride(int32_t uid, float frameRate) {
status_t status;
const int c_uid = IPCThreadState::self()->getCallingUid();
if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) {
- status = mFlinger->setOverrideFrameRate(uid, frameRate);
+ status = mFlinger->setGameDefaultFrameRateOverride(uid, frameRate);
} else {
- ALOGE("setOverrideFrameRate() permission denied for uid: %d", c_uid);
+ ALOGE("setGameDefaultFrameRateOverride() permission denied for uid: %d", c_uid);
status = PERMISSION_DENIED;
}
return binderStatusFromStatusT(status);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6909055801..c16489ee00 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -607,7 +607,9 @@ private:
status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface,
const gui::FrameTimelineInfo& frameTimelineInfo);
- status_t setOverrideFrameRate(uid_t uid, float frameRate);
+ status_t setGameModeFrameRateOverride(uid_t uid, float frameRate);
+
+ status_t setGameDefaultFrameRateOverride(uid_t uid, float frameRate);
status_t updateSmallAreaDetection(std::vector<std::pair<int32_t, float>>& uidThresholdMappings);
@@ -1571,7 +1573,8 @@ public:
binder::Status getDisplayDecorationSupport(
const sp<IBinder>& displayToken,
std::optional<gui::DisplayDecorationSupport>* outSupport) override;
- binder::Status setOverrideFrameRate(int32_t uid, float frameRate) override;
+ binder::Status setGameModeFrameRateOverride(int32_t uid, float frameRate) override;
+ binder::Status setGameDefaultFrameRateOverride(int32_t uid, float frameRate) override;
binder::Status enableRefreshRateOverlay(bool active) override;
binder::Status setDebugFlash(int delay) override;
binder::Status scheduleComposite() override;
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index adb497462d..35f5e64c97 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -126,6 +126,7 @@ void FlagManager::dump(std::string& result) const {
DUMP_READ_ONLY_FLAG(enable_fro_dependent_features);
DUMP_READ_ONLY_FLAG(display_protected);
DUMP_READ_ONLY_FLAG(fp16_client_target);
+ DUMP_READ_ONLY_FLAG(game_default_frame_rate);
#undef DUMP_READ_ONLY_FLAG
#undef DUMP_SERVER_FLAG
@@ -201,6 +202,7 @@ FLAG_MANAGER_READ_ONLY_FLAG(cache_if_source_crop_layer_only_moved,
FLAG_MANAGER_READ_ONLY_FLAG(enable_fro_dependent_features, "")
FLAG_MANAGER_READ_ONLY_FLAG(display_protected, "")
FLAG_MANAGER_READ_ONLY_FLAG(fp16_client_target, "debug.sf.fp16_client_target")
+FLAG_MANAGER_READ_ONLY_FLAG(game_default_frame_rate, "")
/// Trunk stable server flags ///
FLAG_MANAGER_SERVER_FLAG(late_boot_misc2, "")
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index cdab461a58..3a509f6352 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -65,6 +65,7 @@ public:
bool enable_fro_dependent_features() const;
bool display_protected() const;
bool fp16_client_target() const;
+ bool game_default_frame_rate() const;
protected:
// overridden for unit tests
diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig
index fabd73846e..ea8dcbbd81 100644
--- a/services/surfaceflinger/surfaceflinger_flags.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags.aconfig
@@ -122,3 +122,11 @@ flag {
bug: "236745178"
is_fixed_read_only: true
}
+
+flag {
+ name: "game_default_frame_rate"
+ namespace: "game"
+ description: "This flag guards the new behavior with the addition of Game Default Frame Rate feature."
+ bug: "286084594"
+ is_fixed_read_only: true
+}
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 5888a55530..5449aeb6bb 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -55,7 +55,6 @@ cc_test {
"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 e43ef952d6..0000000000
--- 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 a581c7a4a4..7c1d4b4092 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 @@ protected:
};
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, testUpdateFrameRateOverridesByContent) {
}
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, testSetPreferredRefreshRateForUid) {
}
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 @@ TEST_F(FrameRateOverrideMappingsTest, testGetFrameRateOverrideForUidMixed) {
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 b88ef563c3..0ae3ca33b1 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -118,6 +118,9 @@ protected:
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, oneLayer) {
}
}
+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 3dfb649a02..4204aa0001 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 @@ public:
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*());