diff options
author | 2021-11-18 14:51:06 -0800 | |
---|---|---|
committer | 2022-01-18 17:46:59 -0800 | |
commit | 2ae6b6bc57089a726edf6ef7cc8582ec524c736f (patch) | |
tree | 7d18c1287dbfb46fc6cb71ac085c77c1fab62783 | |
parent | 338ee42d6eb20132ba98cb4dadeb6ff08bcd0b7a (diff) |
Implement game mode framerate override
Add logic for setting throttling framerate requested
by Game Dashboard interventions.
- Refactored of FrameRateOverrideMappings in Scheduler
- Have mSupportsFrameRateOverride only guard mFrameRateOverrideByContent
- Remove logic that disables framerate override when it's not a divider
Bug: b/204322816
Test: atest FrameRateOverrideHostTest
Change-Id: I1a2caf378cd87ce4830f6fc48332b5df518330cc
-rw-r--r-- | libs/gui/ISurfaceComposer.cpp | 26 | ||||
-rw-r--r-- | libs/gui/SurfaceComposerClient.cpp | 4 | ||||
-rw-r--r-- | libs/gui/include/gui/ISurfaceComposer.h | 8 | ||||
-rw-r--r-- | libs/gui/include/gui/SurfaceComposerClient.h | 4 | ||||
-rw-r--r-- | libs/gui/tests/Surface_test.cpp | 4 | ||||
-rw-r--r-- | services/surfaceflinger/Android.bp | 1 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp | 137 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h | 55 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp | 13 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/RefreshRateConfigs.h | 4 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/Scheduler.cpp | 90 | ||||
-rw-r--r-- | services/surfaceflinger/Scheduler/Scheduler.h | 27 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 12 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 2 |
14 files changed, 292 insertions, 95 deletions
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 02270433b6..b7594df2fb 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -1346,6 +1346,21 @@ public: SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(windowInfosListener)); return remote()->transact(BnSurfaceComposer::REMOVE_WINDOW_INFOS_LISTENER, data, &reply); } + + status_t setOverrideFrameRate(uid_t uid, float frameRate) override { + Parcel data, reply; + SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); + SAFE_PARCEL(data.writeUint32, uid); + SAFE_PARCEL(data.writeFloat, frameRate); + + status_t err = remote()->transact(BnSurfaceComposer::SET_OVERRIDE_FRAME_RATE, data, &reply); + if (err != NO_ERROR) { + ALOGE("setOverrideFrameRate: failed to transact %s (%d)", strerror(-err), err); + return err; + } + + return NO_ERROR; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -2306,6 +2321,17 @@ status_t BnSurfaceComposer::onTransact( return removeWindowInfosListener(listener); } + case SET_OVERRIDE_FRAME_RATE: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + + uid_t uid; + SAFE_PARCEL(data.readUint32, &uid); + + float frameRate; + SAFE_PARCEL(data.readFloat, &frameRate); + + return setOverrideFrameRate(uid, frameRate); + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index b4f6cd513c..31456cda7e 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2094,6 +2094,10 @@ status_t SurfaceComposerClient::getPreferredBootDisplayMode(const sp<IBinder>& d displayModeId); } +status_t SurfaceComposerClient::setOverrideFrameRate(uid_t uid, float frameRate) { + return ComposerService::getComposerService()->setOverrideFrameRate(uid, frameRate); +} + void SurfaceComposerClient::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) { ComposerService::getComposerService()->setAutoLowLatencyMode(display, on); } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index f37580c491..fb4fb7e2da 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -559,6 +559,13 @@ public: int8_t compatibility, int8_t changeFrameRateStrategy) = 0; /* + * Set the override frame rate for a specified uid by GameManagerService. + * Passing the frame rate and uid to SurfaceFlinger to update the override mapping + * in the scheduler. + */ + virtual status_t setOverrideFrameRate(uid_t uid, float frameRate) = 0; + + /* * Sets the frame timeline vsync info received from choreographer that corresponds to next * buffer submitted on that surface. */ @@ -678,6 +685,7 @@ public: SET_BOOT_DISPLAY_MODE, CLEAR_BOOT_DISPLAY_MODE, GET_PREFERRED_BOOT_DISPLAY_MODE, + SET_OVERRIDE_FRAME_RATE, // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index c1923232df..4f928781d9 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -25,6 +25,7 @@ #include <binder/IBinder.h> +#include <utils/Errors.h> #include <utils/RefBase.h> #include <utils/Singleton.h> #include <utils/SortedVector.h> @@ -175,6 +176,9 @@ public: static status_t clearBootDisplayMode(const sp<IBinder>& display); // Gets the display mode in which the device boots if there is no user-preferred display mode static status_t getPreferredBootDisplayMode(const sp<IBinder>& display, ui::DisplayModeId*); + // Sets the frame rate of a particular app (uid). This is currently called + // by GameManager. + static status_t setOverrideFrameRate(uid_t uid, float frameRate); // Switches on/off Auto Low Latency Mode on the connected display. This should only be // called if the connected display supports Auto Low Latency Mode as reported by diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 999874bd05..0ebd11cf32 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -31,9 +31,11 @@ #include <gui/SyncScreenCaptureListener.h> #include <inttypes.h> #include <private/gui/ComposerService.h> +#include <sys/types.h> #include <ui/BufferQueueDefs.h> #include <ui/DisplayMode.h> #include <ui/Rect.h> +#include <utils/Errors.h> #include <utils/String8.h> #include <limits> @@ -925,6 +927,8 @@ public: return NO_ERROR; } + status_t setOverrideFrameRate(uid_t /*uid*/, float /*frameRate*/) override { return NO_ERROR; } + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 3e6d49f360..a4dd32d92f 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -183,6 +183,7 @@ filegroup { "RenderArea.cpp", "Scheduler/DispSyncSource.cpp", "Scheduler/EventThread.cpp", + "Scheduler/FrameRateOverrideMappings.cpp", "Scheduler/OneShotTimer.cpp", "Scheduler/LayerHistory.cpp", "Scheduler/LayerInfo.cpp", diff --git a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp new file mode 100644 index 0000000000..d9d64ae9db --- /dev/null +++ b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.cpp @@ -0,0 +1,137 @@ +/* + * Copyright 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 "FrameRateOverrideMappings.h" + +namespace android::scheduler { +using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; + +std::optional<Fps> FrameRateOverrideMappings::getFrameRateOverrideForUid( + uid_t uid, bool supportsFrameRateOverrideByContent) const { + std::lock_guard lock(mFrameRateOverridesLock); + + { + const auto iter = mFrameRateOverridesFromBackdoor.find(uid); + if (iter != mFrameRateOverridesFromBackdoor.end()) { + return iter->second; + } + } + + { + const auto iter = mFrameRateOverridesFromGameManager.find(uid); + if (iter != mFrameRateOverridesFromGameManager.end()) { + return iter->second; + } + } + + if (!supportsFrameRateOverrideByContent) { + return std::nullopt; + } + + { + const auto iter = mFrameRateOverridesByContent.find(uid); + if (iter != mFrameRateOverridesByContent.end()) { + return iter->second; + } + } + + return std::nullopt; +} + +std::vector<FrameRateOverride> FrameRateOverrideMappings::getAllFrameRateOverrides() { + std::lock_guard lock(mFrameRateOverridesLock); + std::vector<FrameRateOverride> overrides; + overrides.reserve(std::max({mFrameRateOverridesFromGameManager.size(), + mFrameRateOverridesFromBackdoor.size(), + mFrameRateOverridesByContent.size()})); + + 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()}); + } + } + for (const auto& [uid, frameRate] : mFrameRateOverridesByContent) { + 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()}); + } + } + + return overrides; +} + +void FrameRateOverrideMappings::dump(std::string& result) const { + using base::StringAppendF; + + std::lock_guard lock(mFrameRateOverridesLock); + + StringAppendF(&result, "Frame Rate Overrides (backdoor): {"); + for (const auto& [uid, frameRate] : mFrameRateOverridesFromBackdoor) { + StringAppendF(&result, "[uid: %d frameRate: %s], ", uid, to_string(frameRate).c_str()); + } + StringAppendF(&result, "}\n"); + + StringAppendF(&result, "Frame Rate Overrides (GameManager): {"); + for (const auto& [uid, frameRate] : mFrameRateOverridesFromGameManager) { + StringAppendF(&result, "[uid: %d frameRate: %s], ", uid, to_string(frameRate).c_str()); + } + StringAppendF(&result, "}\n"); + + StringAppendF(&result, "Frame Rate Overrides (setFrameRate): {"); + for (const auto& [uid, frameRate] : mFrameRateOverridesByContent) { + StringAppendF(&result, "[uid: %d frameRate: %s], ", uid, to_string(frameRate).c_str()); + } + StringAppendF(&result, "}\n"); +} + +bool FrameRateOverrideMappings::updateFrameRateOverridesByContent( + const UidToFrameRateOverride& frameRateOverrides) { + std::lock_guard lock(mFrameRateOverridesLock); + if (!std::equal(mFrameRateOverridesByContent.begin(), mFrameRateOverridesByContent.end(), + frameRateOverrides.begin(), frameRateOverrides.end(), + [](const auto& lhs, const auto& rhs) { + return lhs.first == rhs.first && isApproxEqual(lhs.second, rhs.second); + })) { + mFrameRateOverridesByContent = frameRateOverrides; + return true; + } + return false; +} + +void FrameRateOverrideMappings::setGameModeRefreshRateForUid(FrameRateOverride frameRateOverride) { + std::lock_guard lock(mFrameRateOverridesLock); + if (frameRateOverride.frameRateHz != 0.f) { + mFrameRateOverridesFromGameManager[frameRateOverride.uid] = + Fps::fromValue(frameRateOverride.frameRateHz); + } else { + mFrameRateOverridesFromGameManager.erase(frameRateOverride.uid); + } +} + +void FrameRateOverrideMappings::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverride) { + std::lock_guard lock(mFrameRateOverridesLock); + if (frameRateOverride.frameRateHz != 0.f) { + mFrameRateOverridesFromBackdoor[frameRateOverride.uid] = + Fps::fromValue(frameRateOverride.frameRateHz); + } else { + mFrameRateOverridesFromBackdoor.erase(frameRateOverride.uid); + } +} +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h new file mode 100644 index 0000000000..278f87c30f --- /dev/null +++ b/services/surfaceflinger/Scheduler/FrameRateOverrideMappings.h @@ -0,0 +1,55 @@ +/* + * Copyright 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. + */ + +#pragma once + +#include <android-base/thread_annotations.h> +#include <gui/DisplayEventReceiver.h> +#include <scheduler/Fps.h> +#include <sys/types.h> +#include <map> +#include <optional> + +namespace android::scheduler { +class FrameRateOverrideMappings { + using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; + using UidToFrameRateOverride = std::map<uid_t, Fps>; + +public: + std::optional<Fps> getFrameRateOverrideForUid(uid_t uid, + bool supportsFrameRateOverrideByContent) const + EXCLUDES(mFrameRateOverridesLock); + std::vector<FrameRateOverride> getAllFrameRateOverrides() EXCLUDES(mFrameRateOverridesLock); + void dump(std::string& result) const; + bool updateFrameRateOverridesByContent(const UidToFrameRateOverride& frameRateOverrides) + EXCLUDES(mFrameRateOverridesLock); + void setGameModeRefreshRateForUid(FrameRateOverride frameRateOverride) + EXCLUDES(mFrameRateOverridesLock); + void setPreferredRefreshRateForUid(FrameRateOverride frameRateOverride) + EXCLUDES(mFrameRateOverridesLock); + +private: + // The frame rate override lists need their own mutex as they are being read + // by SurfaceFlinger, Scheduler and EventThread (as a callback) to prevent deadlocks + mutable std::mutex mFrameRateOverridesLock; + + // mappings between a UID and a preferred refresh rate that this app would + // run at. + UidToFrameRateOverride mFrameRateOverridesByContent GUARDED_BY(mFrameRateOverridesLock); + UidToFrameRateOverride mFrameRateOverridesFromBackdoor GUARDED_BY(mFrameRateOverridesLock); + UidToFrameRateOverride mFrameRateOverridesFromGameManager GUARDED_BY(mFrameRateOverridesLock); +}; +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index a94952f415..eaec789257 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -206,7 +206,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye if (layer.vote == LayerVoteType::ExplicitExact) { const int divider = getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate); - if (mSupportsFrameRateOverride) { + if (mSupportsFrameRateOverrideByContent) { // Since we support frame rate override, allow refresh rates which are // multiples of the layer's request, as those apps would be throttled // down to run at the desired refresh rate. @@ -479,7 +479,7 @@ RefreshRate RefreshRateConfigs::getBestRefreshRateLocked( const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); const bool touchBoostForExplicitExact = [&] { - if (mSupportsFrameRateOverride) { + if (mSupportsFrameRateOverrideByContent) { // Enable touch boost if there are other layers besides exact return explicitExact + noVoteLayers != layers.size(); } else { @@ -547,7 +547,6 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr const std::vector<LayerRequirement>& layers, Fps displayFrameRate, GlobalSignals globalSignals) const { ATRACE_CALL(); - if (!mSupportsFrameRateOverride) return {}; ALOGV("getFrameRateOverrides %zu layers", layers.size()); std::lock_guard lock(mLock); @@ -762,12 +761,12 @@ void RefreshRateConfigs::updateDisplayModes(const DisplayModes& modes, mMinSupportedRefreshRate = sortedModes.front(); mMaxSupportedRefreshRate = sortedModes.back(); - mSupportsFrameRateOverride = false; + mSupportsFrameRateOverrideByContent = false; if (mConfig.enableFrameRateOverride) { for (const auto& mode1 : sortedModes) { for (const auto& mode2 : sortedModes) { if (getFrameRateDivider(mode1->getFps(), mode2->getFps()) >= 2) { - mSupportsFrameRateOverride = true; + mSupportsFrameRateOverrideByContent = true; break; } } @@ -1006,8 +1005,8 @@ void RefreshRateConfigs::dump(std::string& result) const { base::StringAppendF(&result, "\t%s\n", refreshRate->toString().c_str()); } - base::StringAppendF(&result, "Supports Frame Rate Override: %s\n", - mSupportsFrameRateOverride ? "yes" : "no"); + base::StringAppendF(&result, "Supports Frame Rate Override By Content: %s\n", + mSupportsFrameRateOverrideByContent ? "yes" : "no"); base::StringAppendF(&result, "Idle timer: (%s) %s\n", mConfig.supportKernelIdleTimer ? "kernel" : "platform", mIdleTimer ? mIdleTimer->dump().c_str() : "off"); diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index fc45d2b909..ff36eee075 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -328,7 +328,7 @@ public: // refresh rates. KernelIdleTimerAction getIdleTimerAction() const; - bool supportsFrameRateOverride() const { return mSupportsFrameRateOverride; } + bool supportsFrameRateOverrideByContent() const { return mSupportsFrameRateOverrideByContent; } // Return the display refresh rate divider to match the layer // frame rate, or 0 if the display refresh rate is not a multiple of the @@ -496,7 +496,7 @@ private: const std::vector<Fps> mKnownFrameRates; const Config mConfig; - bool mSupportsFrameRateOverride; + bool mSupportsFrameRateOverrideByContent; struct GetBestRefreshRateInvocation { std::vector<LayerRequirement> layerRequirements; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 4173088d99..48d54318e1 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -42,6 +42,7 @@ #include "../Layer.h" #include "DispSyncSource.h" #include "EventThread.h" +#include "FrameRateOverrideMappings.h" #include "InjectVSyncSource.h" #include "OneShotTimer.h" #include "SchedulerUtils.h" @@ -139,29 +140,11 @@ std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource( } std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const { - { - std::scoped_lock lock(mRefreshRateConfigsLock); - if (!mRefreshRateConfigs->supportsFrameRateOverride()) { - return std::nullopt; - } - } - - std::lock_guard lock(mFrameRateOverridesLock); - { - const auto iter = mFrameRateOverridesFromBackdoor.find(uid); - if (iter != mFrameRateOverridesFromBackdoor.end()) { - return iter->second; - } - } - - { - const auto iter = mFrameRateOverridesByContent.find(uid); - if (iter != mFrameRateOverridesByContent.end()) { - return iter->second; - } - } - - return std::nullopt; + const auto refreshRateConfigs = holdRefreshRateConfigs(); + const bool supportsFrameRateOverrideByContent = + refreshRateConfigs->supportsFrameRateOverrideByContent(); + return mFrameRateOverrideMappings + .getFrameRateOverrideForUid(uid, supportsFrameRateOverrideByContent); } bool Scheduler::isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const { @@ -175,9 +158,6 @@ bool Scheduler::isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const { impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const { std::scoped_lock lock(mRefreshRateConfigsLock); - if (!mRefreshRateConfigs->supportsFrameRateOverride()) { - return {}; - } return [this](nsecs_t expectedVsyncTimestamp, uid_t uid) { return !isVsyncValid(expectedVsyncTimestamp, uid); @@ -283,18 +263,9 @@ void Scheduler::onScreenReleased(ConnectionHandle handle) { } void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDisplayId displayId) { - std::vector<FrameRateOverride> overrides; - { - std::lock_guard lock(mFrameRateOverridesLock); - for (const auto& [uid, frameRate] : mFrameRateOverridesFromBackdoor) { - overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()}); - } - for (const auto& [uid, frameRate] : mFrameRateOverridesByContent) { - if (mFrameRateOverridesFromBackdoor.count(uid) == 0) { - overrides.emplace_back(FrameRateOverride{uid, frameRate.getValue()}); - } - } - } + std::vector<FrameRateOverride> overrides = + mFrameRateOverrideMappings.getAllFrameRateOverrides(); + android::EventThread* thread; { std::lock_guard lock(mConnectionsLock); @@ -694,20 +665,7 @@ void Scheduler::dump(std::string& result) const { mFeatures.test(Feature::kContentDetection) ? "on" : "off", mLayerHistory.dump().c_str()); - { - std::lock_guard lock(mFrameRateOverridesLock); - StringAppendF(&result, "Frame Rate Overrides (backdoor): {"); - for (const auto& [uid, frameRate] : mFrameRateOverridesFromBackdoor) { - StringAppendF(&result, "[uid: %d frameRate: %s], ", uid, to_string(frameRate).c_str()); - } - StringAppendF(&result, "}\n"); - - StringAppendF(&result, "Frame Rate Overrides (setFrameRate): {"); - for (const auto& [uid, frameRate] : mFrameRateOverridesByContent) { - StringAppendF(&result, "[uid: %d frameRate: %s], ", uid, to_string(frameRate).c_str()); - } - StringAppendF(&result, "}\n"); - } + mFrameRateOverrideMappings.dump(result); { std::lock_guard lock(mHWVsyncLock); @@ -724,7 +682,7 @@ void Scheduler::dumpVsync(std::string& out) const { bool Scheduler::updateFrameRateOverrides( scheduler::RefreshRateConfigs::GlobalSignals consideredSignals, Fps displayRefreshRate) { const auto refreshRateConfigs = holdRefreshRateConfigs(); - if (!refreshRateConfigs->supportsFrameRateOverride()) { + if (!refreshRateConfigs->supportsFrameRateOverrideByContent()) { return false; } @@ -732,15 +690,7 @@ bool Scheduler::updateFrameRateOverrides( const auto frameRateOverrides = refreshRateConfigs->getFrameRateOverrides(mPolicy.contentRequirements, displayRefreshRate, consideredSignals); - std::lock_guard lock(mFrameRateOverridesLock); - if (!std::equal(mFrameRateOverridesByContent.begin(), mFrameRateOverridesByContent.end(), - frameRateOverrides.begin(), frameRateOverrides.end(), - [](const auto& lhs, const auto& rhs) { - return lhs.first == rhs.first && isApproxEqual(lhs.second, rhs.second); - })) { - mFrameRateOverridesByContent = frameRateOverrides; - return true; - } + return mFrameRateOverrideMappings.updateFrameRateOverridesByContent(frameRateOverrides); } return false; } @@ -852,18 +802,20 @@ void Scheduler::onActiveDisplayAreaChanged(uint32_t displayArea) { mLayerHistory.setDisplayArea(displayArea); } -void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverride) { +void Scheduler::setGameModeRefreshRateForUid(FrameRateOverride frameRateOverride) { if (frameRateOverride.frameRateHz > 0.f && frameRateOverride.frameRateHz < 1.f) { return; } - std::lock_guard lock(mFrameRateOverridesLock); - if (frameRateOverride.frameRateHz != 0.f) { - mFrameRateOverridesFromBackdoor[frameRateOverride.uid] = - Fps::fromValue(frameRateOverride.frameRateHz); - } else { - mFrameRateOverridesFromBackdoor.erase(frameRateOverride.uid); + mFrameRateOverrideMappings.setGameModeRefreshRateForUid(frameRateOverride); +} + +void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverride) { + if (frameRateOverride.frameRateHz > 0.f && frameRateOverride.frameRateHz < 1.f) { + return; } + + mFrameRateOverrideMappings.setPreferredRefreshRateForUid(frameRateOverride); } std::chrono::steady_clock::time_point Scheduler::getPreviousVsyncFrom( diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 548c34b5d2..579fabb400 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -34,6 +34,7 @@ #include <scheduler/Features.h> #include "EventThread.h" +#include "FrameRateOverrideMappings.h" #include "LayerHistory.h" #include "MessageQueue.h" #include "OneShotTimer.h" @@ -117,7 +118,7 @@ public: void onScreenReleased(ConnectionHandle); void onFrameRateOverridesChanged(ConnectionHandle, PhysicalDisplayId) - EXCLUDES(mFrameRateOverridesLock) EXCLUDES(mConnectionsLock); + EXCLUDES(mConnectionsLock); // Modifies work duration in the event thread. void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration, @@ -167,8 +168,7 @@ public: // Returns true if a given vsync timestamp is considered valid vsync // for a given uid - bool isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const - EXCLUDES(mFrameRateOverridesLock); + bool isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const; std::chrono::steady_clock::time_point getPreviousVsyncFrom(nsecs_t expectedPresentTime) const; @@ -197,10 +197,12 @@ public: // Stores the preferred refresh rate that an app should run at. // FrameRateOverride.refreshRateHz == 0 means no preference. - void setPreferredRefreshRateForUid(FrameRateOverride) EXCLUDES(mFrameRateOverridesLock); + void setPreferredRefreshRateForUid(FrameRateOverride); + + void setGameModeRefreshRateForUid(FrameRateOverride); + // Retrieves the overridden refresh rate for a given uid. - std::optional<Fps> getFrameRateOverride(uid_t uid) const - EXCLUDES(mRefreshRateConfigsLock, mFrameRateOverridesLock); + std::optional<Fps> getFrameRateOverride(uid_t uid) const EXCLUDES(mRefreshRateConfigsLock); nsecs_t getVsyncPeriodFromRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) { std::scoped_lock lock(mRefreshRateConfigsLock); @@ -246,7 +248,7 @@ private: void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mRefreshRateConfigsLock); bool updateFrameRateOverrides(RefreshRateConfigs::GlobalSignals, Fps displayRefreshRate) - REQUIRES(mPolicyLock) EXCLUDES(mFrameRateOverridesLock); + REQUIRES(mPolicyLock); impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const EXCLUDES(mRefreshRateConfigsLock); @@ -321,16 +323,7 @@ private: GUARDED_BY(mVsyncTimelineLock); static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms; - // The frame rate override lists need their own mutex as they are being read - // by SurfaceFlinger, Scheduler and EventThread (as a callback) to prevent deadlocks - mutable std::mutex mFrameRateOverridesLock; - - // mappings between a UID and a preferred refresh rate that this app would - // run at. - RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesByContent - GUARDED_BY(mFrameRateOverridesLock); - RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesFromBackdoor - GUARDED_BY(mFrameRateOverridesLock); + FrameRateOverrideMappings mFrameRateOverrideMappings; // Keeps track of whether the screen is acquired for debug std::atomic<bool> mScreenAcquired = false; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 51cb409235..0bb0aa8b7e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5566,6 +5566,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { } return PERMISSION_DENIED; } + case SET_OVERRIDE_FRAME_RATE: case ON_PULL_ATOM: { const int uid = IPCThreadState::self()->getCallingUid(); if (uid == AID_SYSTEM) { @@ -6970,6 +6971,17 @@ status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, return NO_ERROR; } +status_t SurfaceFlinger::setOverrideFrameRate(uid_t uid, float frameRate) { + PhysicalDisplayId displayId = [&]() { + Mutex::Autolock lock(mStateLock); + return getDefaultDisplayDeviceLocked()->getPhysicalId(); + }(); + + mScheduler->setGameModeRefreshRateForUid(FrameRateOverride{static_cast<uid_t>(uid), frameRate}); + mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId); + return NO_ERROR; +} + status_t SurfaceFlinger::setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface, const FrameTimelineInfo& frameTimelineInfo) { Mutex::Autolock lock(mStateLock); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 08d3463d7d..168b0cd5bf 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -603,6 +603,8 @@ private: status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface, const FrameTimelineInfo& frameTimelineInfo) override; + status_t setOverrideFrameRate(uid_t uid, float frameRate) override; + status_t addTransactionTraceListener( const sp<gui::ITransactionTraceListener>& listener) override; |