diff options
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*()); |