From 88930f96e88c4d23fa1265cca3e2fdb7aca4fb52 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 7 Jun 2023 10:32:08 -0700 Subject: SF: improve RenderThread jank classificaion Mark UI frames that didn't make it to their expected presentation due to RenderThread animations as dropped. Screenshot from Perfetto: https://screenshot.googleplex.com/3pQuNaDYAhHLYu7 Bug: 210605870 Test: manual Change-Id: Ibc91bcaac2f9296ec0bddd5deebb4289c5b5bf7e --- libs/gui/SurfaceComposerClient.cpp | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 0fda358b63..5bc05ef0d8 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1027,7 +1027,7 @@ void SurfaceComposerClient::Transaction::clear() { mEarlyWakeupEnd = false; mDesiredPresentTime = 0; mIsAutoTimestamp = true; - clearFrameTimelineInfo(mFrameTimelineInfo); + mFrameTimelineInfo = {}; mApplyToken = nullptr; mMergedTransactionIds.clear(); } @@ -2279,27 +2279,13 @@ void SurfaceComposerClient::Transaction::mergeFrameTimelineInfo(FrameTimelineInf if (t.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID && other.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { if (other.vsyncId > t.vsyncId) { - t.vsyncId = other.vsyncId; - t.inputEventId = other.inputEventId; - t.startTimeNanos = other.startTimeNanos; - t.useForRefreshRateSelection = other.useForRefreshRateSelection; + t = other; } } else if (t.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) { - t.vsyncId = other.vsyncId; - t.inputEventId = other.inputEventId; - t.startTimeNanos = other.startTimeNanos; - t.useForRefreshRateSelection = other.useForRefreshRateSelection; + t = other; } } -// copied from FrameTimelineInfo::clear() -void SurfaceComposerClient::Transaction::clearFrameTimelineInfo(FrameTimelineInfo& t) { - t.vsyncId = FrameTimelineInfo::INVALID_VSYNC_ID; - t.inputEventId = os::IInputConstants::INVALID_INPUT_EVENT_ID; - t.startTimeNanos = 0; - t.useForRefreshRateSelection = false; -} - SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTrustedPresentationCallback( const sp& sc, TrustedPresentationCallback cb, -- cgit v1.2.3-59-g8ed1b From 30da367c6c0781d9783459567ec57d9d10c77c92 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Tue, 25 Jul 2023 16:52:01 -0500 Subject: Ensure transaction commit callbacks are called at most once. Bug: 288781573 Bug: 292443283 Test: atest LayerTransactionTest Change-Id: Ide66601b8a892b4bf5a331d83d38b4bd50919751 --- libs/gui/SurfaceComposerClient.cpp | 6 ++++- .../surfaceflinger/tests/LayerTransaction_test.cpp | 29 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 5bc05ef0d8..db99726739 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -377,7 +377,6 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } auto& [callbackFunction, callbackSurfaceControls] = callbacksMap[callbackId]; if (!callbackFunction) { - ALOGE("cannot call null callback function, skipping"); continue; } std::vector surfaceControlStats; @@ -394,6 +393,11 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener callbackFunction(transactionStats.latchTime, transactionStats.presentFence, surfaceControlStats); + + // More than one transaction may contain the same callback id. Erase the callback from + // the map to ensure that it is only called once. This can happen if transactions are + // parcelled out of process and applied in both processes. + callbacksMap.erase(callbackId); } // handle on complete callbacks diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp index cbd54e7aa9..03de8d0b6d 100644 --- a/services/surfaceflinger/tests/LayerTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp @@ -184,6 +184,35 @@ TEST_F(LayerTransactionTest, BufferTakesPriorityOverColor) { } } +TEST_F(LayerTransactionTest, CommitCallbackCalledOnce) { + auto callCount = 0; + auto commitCallback = + [&callCount](void* /* context */, nsecs_t /* latchTime */, + const sp& /* presentFence */, + const std::vector& /* stats */) mutable { + callCount++; + }; + + // Create two transactions that both contain the same callback id. + Transaction t1; + t1.addTransactionCommittedCallback(commitCallback, nullptr); + Parcel parcel; + t1.writeToParcel(&parcel); + parcel.setDataPosition(0); + Transaction t2; + t2.readFromParcel(&parcel); + + // Apply the two transactions. There is a race here as we can't guarantee that the two + // transactions will be applied within the same SurfaceFlinger commit. If the transactions are + // applied within the same commit then we verify that callback ids are deduplicated within a + // single commit. Otherwise, we verify that commit callbacks are deduplicated across separate + // commits. + t1.apply(); + t2.apply(/*synchronous=*/true); + + ASSERT_EQ(callCount, 1); +} + } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -- cgit v1.2.3-59-g8ed1b From 6f4d2f5423e74ac31a79e3a112a3b31bfb5d2015 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 10 Aug 2023 12:33:12 -0700 Subject: [SurfaceComposerClient] Avoid mSurfaceStats mutex contention Previous logic acquired mSurfaceStats mutex and called the listeners with the mutex held between buffer releases. Instead release all the buffers before handling surface stats listener callbacks and updating jank data. Bug: 294935709 Test: presubmit and perfetto traces Change-Id: Ie90ccde431059bdcdb6900148c6027d313e7434f --- libs/gui/SurfaceComposerClient.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index db99726739..ae0cdc92ac 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -450,7 +450,9 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener callbackFunction(transactionStats.latchTime, transactionStats.presentFence, surfaceControlStats); } + } + for (const auto& transactionStats : listenerStats.transactionStats) { for (const auto& surfaceStats : transactionStats.surfaceStats) { // The callbackMap contains the SurfaceControl object, which we need to look up the // layerId. Since we don't know which callback contains the SurfaceControl, iterate -- cgit v1.2.3-59-g8ed1b From 090ad06d47a8fec09252399f09d86ce4d063f5d1 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Tue, 8 Aug 2023 12:30:10 -0500 Subject: Add getStalledTransactionInfo method to SurfaceComposer Bug: 287577707 Test: presubmits Change-Id: I9c464ee302e7bafe8d45021063368fcd984e27ec --- libs/gui/Android.bp | 2 + libs/gui/SurfaceComposerClient.cpp | 7 ++++ libs/gui/aidl/android/gui/ISurfaceComposer.aidl | 7 ++++ libs/gui/android/gui/StalledTransactionInfo.aidl | 24 +++++++++++ libs/gui/fuzzer/libgui_fuzzer_utils.h | 2 + libs/gui/include/gui/SurfaceComposerClient.h | 4 ++ libs/gui/tests/Surface_test.cpp | 5 +++ .../surfaceflinger/FrontEnd/TransactionHandler.cpp | 39 +++++++++++------ .../surfaceflinger/FrontEnd/TransactionHandler.h | 19 +++++++-- services/surfaceflinger/SurfaceFlinger.cpp | 49 +++++++++++++++++++--- services/surfaceflinger/SurfaceFlinger.h | 5 +++ 11 files changed, 142 insertions(+), 21 deletions(-) create mode 100644 libs/gui/android/gui/StalledTransactionInfo.aidl (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index d7e7eb8ea1..298838d816 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -62,6 +62,7 @@ filegroup { name: "guiconstants_aidl", srcs: [ "android/gui/DropInputMode.aidl", + "android/gui/StalledTransactionInfo.aidl", "android/**/TouchOcclusionMode.aidl", ], } @@ -140,6 +141,7 @@ aidl_library { "android/gui/IWindowInfosListener.aidl", "android/gui/IWindowInfosPublisher.aidl", "android/gui/IWindowInfosReportedListener.aidl", + "android/gui/StalledTransactionInfo.aidl", "android/gui/WindowInfo.aidl", "android/gui/WindowInfosUpdate.aidl", ], diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 6bc3324b7c..1a78b032aa 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1308,6 +1308,13 @@ sp SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId dis return status.isOk() ? display : nullptr; } +std::optional SurfaceComposerClient::getStalledTransactionInfo( + pid_t pid) { + std::optional result; + ComposerServiceAIDL::getComposerService()->getStalledTransactionInfo(pid, &result); + return result; +} + void SurfaceComposerClient::Transaction::setAnimationTransaction() { mAnimation = true; } diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index 5e8e9043c1..f84a910bf8 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -46,6 +46,7 @@ import android.gui.LayerDebugInfo; import android.gui.OverlayProperties; import android.gui.PullAtomData; import android.gui.ARect; +import android.gui.StalledTransactionInfo; import android.gui.StaticDisplayInfo; import android.gui.WindowInfosListenerInfo; @@ -507,4 +508,10 @@ interface ISurfaceComposer { void removeWindowInfosListener(IWindowInfosListener windowInfosListener); OverlayProperties getOverlaySupport(); + + /** + * Returns an instance of StalledTransaction if a transaction from the passed pid has not been + * applied in SurfaceFlinger due to an unsignaled fence. Otherwise, null is returned. + */ + @nullable StalledTransactionInfo getStalledTransactionInfo(int pid); } diff --git a/libs/gui/android/gui/StalledTransactionInfo.aidl b/libs/gui/android/gui/StalledTransactionInfo.aidl new file mode 100644 index 0000000000..e6aa9bd1c7 --- /dev/null +++ b/libs/gui/android/gui/StalledTransactionInfo.aidl @@ -0,0 +1,24 @@ +/* + * Copyright 2023 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. + */ + +package android.gui; + +/** @hide */ +parcelable StalledTransactionInfo { + String layerName; + long bufferId; + long frameNumber; +} \ No newline at end of file diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h index 4c7d0562af..c70197cb23 100644 --- a/libs/gui/fuzzer/libgui_fuzzer_utils.h +++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h @@ -158,6 +158,8 @@ public: MOCK_METHOD(binder::Status, removeWindowInfosListener, (const sp&), (override)); MOCK_METHOD(binder::Status, getOverlaySupport, (gui::OverlayProperties*), (override)); + MOCK_METHOD(binder::Status, getStalledTransactionInfo, + (int32_t, std::optional*), (override)); }; class FakeBnSurfaceComposerClient : public gui::BnSurfaceComposerClient { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 3cf57b11e9..dbcbd3bd62 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -371,6 +371,10 @@ public: //! Get token for a physical display given its stable ID static sp getPhysicalDisplayToken(PhysicalDisplayId displayId); + // Returns StalledTransactionInfo if a transaction from the provided pid has not been applied + // due to an unsignaled fence. + static std::optional getStalledTransactionInfo(pid_t pid); + struct SCHash { std::size_t operator()(const sp& sc) const { return std::hash{}(sc.get()); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 567604dbec..d7910d26aa 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -1016,6 +1016,11 @@ public: return binder::Status::ok(); } + binder::Status getStalledTransactionInfo( + int32_t /*pid*/, std::optional* /*result*/) override { + return binder::Status::ok(); + } + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp index 0d3c6ebd47..ca7c3c25f7 100644 --- a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp +++ b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp @@ -188,21 +188,36 @@ bool TransactionHandler::hasPendingTransactions() { } void TransactionHandler::onTransactionQueueStalled(uint64_t transactionId, - sp& listener, - const std::string& reason) { - if (std::find(mStalledTransactions.begin(), mStalledTransactions.end(), transactionId) != - mStalledTransactions.end()) { - return; - } + StalledTransactionInfo stalledTransactionInfo) { + std::lock_guard lock{mStalledMutex}; + mStalledTransactions.emplace(transactionId, std::move(stalledTransactionInfo)); +} + +void TransactionHandler::removeFromStalledTransactions(uint64_t transactionId) { + std::lock_guard lock{mStalledMutex}; + mStalledTransactions.erase(transactionId); +} - mStalledTransactions.push_back(transactionId); - listener->onTransactionQueueStalled(String8(reason.c_str())); +std::optional +TransactionHandler::getStalledTransactionInfo(pid_t pid) { + std::lock_guard lock{mStalledMutex}; + for (auto [_, stalledTransactionInfo] : mStalledTransactions) { + if (pid == stalledTransactionInfo.pid) { + return stalledTransactionInfo; + } + } + return std::nullopt; } -void TransactionHandler::removeFromStalledTransactions(uint64_t id) { - auto it = std::find(mStalledTransactions.begin(), mStalledTransactions.end(), id); - if (it != mStalledTransactions.end()) { - mStalledTransactions.erase(it); +void TransactionHandler::onLayerDestroyed(uint32_t layerId) { + std::lock_guard lock{mStalledMutex}; + for (auto it = mStalledTransactions.begin(); it != mStalledTransactions.end();) { + if (it->second.layerId == layerId) { + it = mStalledTransactions.erase(it); + } else { + it++; + } } } + } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.h b/services/surfaceflinger/FrontEnd/TransactionHandler.h index 04183bcdb8..00f6bcebe6 100644 --- a/services/surfaceflinger/FrontEnd/TransactionHandler.h +++ b/services/surfaceflinger/FrontEnd/TransactionHandler.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -63,9 +64,18 @@ public: std::vector flushTransactions(); void addTransactionReadyFilter(TransactionFilter&&); void queueTransaction(TransactionState&&); - void onTransactionQueueStalled(uint64_t transactionId, sp&, - const std::string& reason); + + struct StalledTransactionInfo { + pid_t pid; + uint32_t layerId; + std::string layerName; + uint64_t bufferId; + uint64_t frameNumber; + }; + void onTransactionQueueStalled(uint64_t transactionId, StalledTransactionInfo); void removeFromStalledTransactions(uint64_t transactionId); + std::optional getStalledTransactionInfo(pid_t pid); + void onLayerDestroyed(uint32_t layerId); private: // For unit tests @@ -81,7 +91,10 @@ private: LocklessQueue mLocklessTransactionQueue; std::atomic mPendingTransactionCount = 0; ftl::SmallVector mTransactionReadyFilters; - std::vector mStalledTransactions; + + std::mutex mStalledMutex; + std::unordered_map mStalledTransactions + GUARDED_BY(mStalledMutex); }; } // namespace surfaceflinger::frontend } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e459f03f07..c943d0ac69 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4461,9 +4461,13 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC (flushState.queueProcessTime - transaction.postTime) > std::chrono::nanoseconds(4s).count()) { mTransactionHandler - .onTransactionQueueStalled(transaction.id, listener, - "Buffer processing hung up due to stuck " - "fence. Indicates GPU hang"); + .onTransactionQueueStalled(transaction.id, + {.pid = layer->getOwnerPid(), + .layerId = static_cast( + layer->getSequence()), + .layerName = layer->getDebugName(), + .bufferId = s.bufferData->getId(), + .frameNumber = s.bufferData->frameNumber}); } ATRACE_FORMAT("fence unsignaled %s", layer->getDebugName()); return TraverseBuffersReturnValues::STOP_TRAVERSAL; @@ -4556,9 +4560,12 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC (flushState.queueProcessTime - transaction.postTime) > std::chrono::nanoseconds(4s).count()) { mTransactionHandler - .onTransactionQueueStalled(transaction.id, listener, - "Buffer processing hung up due to stuck " - "fence. Indicates GPU hang"); + .onTransactionQueueStalled(transaction.id, + {.pid = layer->ownerPid.val(), + .layerId = layer->id, + .layerName = layer->name, + .bufferId = s.bufferData->getId(), + .frameNumber = s.bufferData->frameNumber}); } ATRACE_FORMAT("fence unsignaled %s", layer->name.c_str()); return TraverseBuffersReturnValues::STOP_TRAVERSAL; @@ -5585,6 +5592,8 @@ void SurfaceFlinger::onHandleDestroyed(BBinder* handle, sp& layer, uint32 mDestroyedHandles.emplace_back(layerId); } + mTransactionHandler.onLayerDestroyed(layerId); + Mutex::Autolock lock(mStateLock); markLayerPendingRemovalLocked(layer); layer->onHandleDestroyed(); @@ -8390,6 +8399,12 @@ status_t SurfaceFlinger::removeWindowInfosListener( return NO_ERROR; } +status_t SurfaceFlinger::getStalledTransactionInfo( + int pid, std::optional& result) { + result = mTransactionHandler.getStalledTransactionInfo(pid); + return NO_ERROR; +} + std::shared_ptr SurfaceFlinger::getExternalTextureFromBufferData( BufferData& bufferData, const char* layerName, uint64_t transactionId) { if (bufferData.buffer && @@ -9499,6 +9514,28 @@ binder::Status SurfaceComposerAIDL::removeWindowInfosListener( return binderStatusFromStatusT(status); } +binder::Status SurfaceComposerAIDL::getStalledTransactionInfo( + int pid, std::optional* outInfo) { + const int callingPid = IPCThreadState::self()->getCallingPid(); + const int callingUid = IPCThreadState::self()->getCallingUid(); + if (!checkPermission(sAccessSurfaceFlinger, callingPid, callingUid)) { + return binderStatusFromStatusT(PERMISSION_DENIED); + } + + std::optional stalledTransactionInfo; + status_t status = mFlinger->getStalledTransactionInfo(pid, stalledTransactionInfo); + if (stalledTransactionInfo) { + gui::StalledTransactionInfo result; + result.layerName = String16{stalledTransactionInfo->layerName.c_str()}, + result.bufferId = stalledTransactionInfo->bufferId, + result.frameNumber = stalledTransactionInfo->frameNumber, + outInfo->emplace(std::move(result)); + } else { + outInfo->reset(); + } + return binderStatusFromStatusT(status); +} + status_t SurfaceComposerAIDL::checkAccessPermission(bool usePermissionCache) { if (!mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) { IPCThreadState* ipc = IPCThreadState::self(); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index d9c1101de8..3ba1bcba00 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -622,6 +622,9 @@ private: status_t removeWindowInfosListener( const sp& windowInfosListener) const; + status_t getStalledTransactionInfo( + int pid, std::optional& result); + // Implements IBinder::DeathRecipient. void binderDied(const wp& who) override; @@ -1560,6 +1563,8 @@ public: gui::WindowInfosListenerInfo* outInfo) override; binder::Status removeWindowInfosListener( const sp& windowInfosListener) override; + binder::Status getStalledTransactionInfo(int pid, + std::optional* outInfo); private: static const constexpr bool kUsePermissionCache = true; -- cgit v1.2.3-59-g8ed1b From b19fe0c95b0f5d15168a0e0bac0cd5eba0890050 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Fri, 11 Aug 2023 00:06:51 +0000 Subject: Use String8/16 c_str [graphics] Bug: 295394788 Test: make checkbuild Change-Id: I69aa06b109c2f40ecf40441cbbb0dfa3e1aa99a1 --- libs/gui/BufferItemConsumer.cpp | 10 ++--- libs/gui/BufferQueueConsumer.cpp | 15 +++---- libs/gui/BufferQueueCore.cpp | 51 +++++++++++----------- libs/gui/BufferQueueProducer.cpp | 23 +++++----- libs/gui/ConsumerBase.cpp | 18 ++++---- libs/gui/CpuConsumer.cpp | 10 ++--- libs/gui/GLConsumer.cpp | 10 ++--- libs/gui/SurfaceComposerClient.cpp | 2 +- libs/gui/include/gui/BufferQueueCore.h | 14 +++--- .../gui/bufferqueue/1.0/WGraphicBufferProducer.h | 2 +- libs/gui/tests/GLTest.cpp | 8 ++-- libs/gui/tests/SurfaceTextureFBO_test.cpp | 2 +- libs/gui/tests/SurfaceTextureGL_test.cpp | 7 +-- libs/gui/tests/Surface_test.cpp | 2 +- libs/nativedisplay/surfacetexture/EGLConsumer.cpp | 8 ++-- .../nativedisplay/surfacetexture/ImageConsumer.cpp | 2 +- .../surfacetexture/SurfaceTexture.cpp | 8 ++-- libs/renderengine/skia/GLExtensions.cpp | 12 ++--- libs/ui/Fence.cpp | 2 +- services/gpuservice/GpuService.cpp | 2 +- .../CompositionEngine/src/planner/LayerState.cpp | 2 +- .../CompositionEngine/src/planner/Planner.cpp | 30 ++++++------- services/surfaceflinger/SurfaceFlinger.cpp | 4 +- .../unittests/SurfaceFlinger_CreateDisplayTest.cpp | 4 +- .../surfaceflinger/tests/utils/ScreenshotUtils.h | 2 +- 25 files changed, 125 insertions(+), 125 deletions(-) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index f50bc203e8..e6331e7282 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -24,11 +24,11 @@ #include #include -#define BI_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define BI_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define BI_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define BI_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) -#define BI_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) +#define BI_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define BI_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define BI_LOGI(x, ...) ALOGI("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define BI_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define BI_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__) namespace android { diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 52172090af..5b34ba12c8 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -47,23 +47,23 @@ namespace android { // Macros for include BufferQueueCore information in log messages #define BQ_LOGV(x, ...) \ - ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) #define BQ_LOGD(x, ...) \ - ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) #define BQ_LOGI(x, ...) \ - ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) #define BQ_LOGW(x, ...) \ - ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) #define BQ_LOGE(x, ...) \ - ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) @@ -298,8 +298,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, // decrease. mCore->mDequeueCondition.notify_all(); - ATRACE_INT(mCore->mConsumerName.string(), - static_cast(mCore->mQueue.size())); + ATRACE_INT(mCore->mConsumerName.c_str(), static_cast(mCore->mQueue.size())); #ifndef NO_BINDER mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size()); #endif @@ -718,7 +717,7 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount( status_t BufferQueueConsumer::setConsumerName(const String8& name) { ATRACE_CALL(); - BQ_LOGV("setConsumerName: '%s'", name.string()); + BQ_LOGV("setConsumerName: '%s'", name.c_str()); std::lock_guard lock(mCore->mMutex); mCore->mConsumerName = name; mConsumerName = name; diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index 2930154ad4..648db67fc1 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -41,20 +41,20 @@ namespace android { // Macros for include BufferQueueCore information in log messages -#define BQ_LOGV(x, ...) \ - ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ +#define BQ_LOGV(x, ...) \ + ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \ mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) -#define BQ_LOGD(x, ...) \ - ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ +#define BQ_LOGD(x, ...) \ + ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \ mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) -#define BQ_LOGI(x, ...) \ - ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ +#define BQ_LOGI(x, ...) \ + ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \ mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) -#define BQ_LOGW(x, ...) \ - ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ +#define BQ_LOGW(x, ...) \ + ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \ mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) -#define BQ_LOGE(x, ...) \ - ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), mUniqueId, \ +#define BQ_LOGE(x, ...) \ + ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), mUniqueId, \ mConnectedApi, mConnectedPid, mUniqueId >> 32, ##__VA_ARGS__) static String8 getUniqueName() { @@ -146,23 +146,23 @@ BufferQueueCore::~BufferQueueCore() {} void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const { std::lock_guard lock(mMutex); - outResult->appendFormat("%s- BufferQueue ", prefix.string()); + outResult->appendFormat("%s- BufferQueue ", prefix.c_str()); outResult->appendFormat("mMaxAcquiredBufferCount=%d mMaxDequeuedBufferCount=%d\n", mMaxAcquiredBufferCount, mMaxDequeuedBufferCount); - outResult->appendFormat("%s mDequeueBufferCannotBlock=%d mAsyncMode=%d\n", prefix.string(), + outResult->appendFormat("%s mDequeueBufferCannotBlock=%d mAsyncMode=%d\n", prefix.c_str(), mDequeueBufferCannotBlock, mAsyncMode); - outResult->appendFormat("%s mQueueBufferCanDrop=%d mLegacyBufferDrop=%d\n", prefix.string(), + outResult->appendFormat("%s mQueueBufferCanDrop=%d mLegacyBufferDrop=%d\n", prefix.c_str(), mQueueBufferCanDrop, mLegacyBufferDrop); - outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.string(), + outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.c_str(), mDefaultWidth, mDefaultHeight, mDefaultBufferFormat); - outResult->appendFormat("%s transform-hint=%02x frame-counter=%" PRIu64 "\n", prefix.string(), + outResult->appendFormat("%s transform-hint=%02x frame-counter=%" PRIu64 "\n", prefix.c_str(), mTransformHint, mFrameCounter); - outResult->appendFormat("%s mTransformHintInUse=%02x mAutoPrerotation=%d\n", prefix.string(), + outResult->appendFormat("%s mTransformHintInUse=%02x mAutoPrerotation=%d\n", prefix.c_str(), mTransformHintInUse, mAutoPrerotation); - outResult->appendFormat("%sFIFO(%zu):\n", prefix.string(), mQueue.size()); + outResult->appendFormat("%sFIFO(%zu):\n", prefix.c_str(), mQueue.size()); - outResult->appendFormat("%s(mConsumerName=%s, ", prefix.string(), mConsumerName.string()); + outResult->appendFormat("%s(mConsumerName=%s, ", prefix.c_str(), mConsumerName.c_str()); outResult->appendFormat("mConnectedApi=%d, mConsumerUsageBits=%" PRIu64 ", ", mConnectedApi, mConsumerUsageBits); @@ -173,12 +173,11 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const getProcessName(mConnectedPid, producerProcName); getProcessName(pid, consumerProcName); outResult->appendFormat("mId=%" PRIx64 ", producer=[%d:%s], consumer=[%d:%s])\n", mUniqueId, - mConnectedPid, producerProcName.string(), pid, - consumerProcName.string()); + mConnectedPid, producerProcName.c_str(), pid, consumerProcName.c_str()); Fifo::const_iterator current(mQueue.begin()); while (current != mQueue.end()) { double timestamp = current->mTimestamp / 1e9; - outResult->appendFormat("%s %02d:%p ", prefix.string(), current->mSlot, + outResult->appendFormat("%s %02d:%p ", prefix.c_str(), current->mSlot, current->mGraphicBuffer.get()); outResult->appendFormat("crop=[%d,%d,%d,%d] ", current->mCrop.left, current->mCrop.top, current->mCrop.right, current->mCrop.bottom); @@ -187,12 +186,12 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const ++current; } - outResult->appendFormat("%sSlots:\n", prefix.string()); + outResult->appendFormat("%sSlots:\n", prefix.c_str()); for (int s : mActiveBuffers) { const sp& buffer(mSlots[s].mGraphicBuffer); // A dequeued buffer might be null if it's still being allocated if (buffer.get()) { - outResult->appendFormat("%s %s[%02d:%p] ", prefix.string(), + outResult->appendFormat("%s %s[%02d:%p] ", prefix.c_str(), (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s, buffer.get()); outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(), @@ -200,14 +199,14 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height, buffer->stride, buffer->format); } else { - outResult->appendFormat("%s [%02d:%p] ", prefix.string(), s, buffer.get()); + outResult->appendFormat("%s [%02d:%p] ", prefix.c_str(), s, buffer.get()); outResult->appendFormat("state=%-8s frame=%" PRIu64 "\n", mSlots[s].mBufferState.string(), mSlots[s].mFrameNumber); } } for (int s : mFreeBuffers) { const sp& buffer(mSlots[s].mGraphicBuffer); - outResult->appendFormat("%s [%02d:%p] ", prefix.string(), s, buffer.get()); + outResult->appendFormat("%s [%02d:%p] ", prefix.c_str(), s, buffer.get()); outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(), buffer->handle, mSlots[s].mFrameNumber); outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height, @@ -216,7 +215,7 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const for (int s : mFreeSlots) { const sp& buffer(mSlots[s].mGraphicBuffer); - outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s, buffer.get(), + outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.c_str(), s, buffer.get(), mSlots[s].mBufferState.string()); } } diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index b872541fec..10f5899b68 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -47,23 +47,23 @@ namespace android { // Macros for include BufferQueueCore information in log messages #define BQ_LOGV(x, ...) \ - ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGV("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) #define BQ_LOGD(x, ...) \ - ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGD("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) #define BQ_LOGI(x, ...) \ - ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGI("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) #define BQ_LOGW(x, ...) \ - ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGW("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) #define BQ_LOGE(x, ...) \ - ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.string(), \ + ALOGE("[%s](id:%" PRIx64 ",api:%d,p:%d,c:%" PRIu64 ") " x, mConsumerName.c_str(), \ mCore->mUniqueId, mCore->mConnectedApi, mCore->mConnectedPid, (mCore->mUniqueId) >> 32, \ ##__VA_ARGS__) @@ -573,9 +573,9 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp* ou if (returnFlags & BUFFER_NEEDS_REALLOCATION) { BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot); - sp graphicBuffer = new GraphicBuffer( - width, height, format, BQ_LAYER_COUNT, usage, - {mConsumerName.string(), mConsumerName.size()}); + sp graphicBuffer = + new GraphicBuffer(width, height, format, BQ_LAYER_COUNT, usage, + {mConsumerName.c_str(), mConsumerName.size()}); status_t error = graphicBuffer->initCheck(); @@ -1046,8 +1046,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, output->numPendingBuffers = static_cast(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; - ATRACE_INT(mCore->mConsumerName.string(), - static_cast(mCore->mQueue.size())); + ATRACE_INT(mCore->mConsumerName.c_str(), static_cast(mCore->mQueue.size())); #ifndef NO_BINDER mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size()); #endif @@ -1487,7 +1486,7 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat; allocUsage = usage | mCore->mConsumerUsageBits; - allocName.assign(mCore->mConsumerName.string(), mCore->mConsumerName.size()); + allocName.assign(mCore->mConsumerName.c_str(), mCore->mConsumerName.size()); mCore->mIsAllocating = true; } // Autolock scope @@ -1589,7 +1588,7 @@ status_t BufferQueueProducer::setGenerationNumber(uint32_t generationNumber) { String8 BufferQueueProducer::getConsumerName() const { ATRACE_CALL(); std::lock_guard lock(mCore->mMutex); - BQ_LOGV("getConsumerName: %s", mConsumerName.string()); + BQ_LOGV("getConsumerName: %s", mConsumerName.c_str()); return mConsumerName; } diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 9f91d9d3aa..b625c3f75e 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -41,11 +41,11 @@ #include // Macros for including the ConsumerBase name in log messages -#define CB_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define CB_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define CB_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define CB_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) -#define CB_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) +#define CB_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define CB_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define CB_LOGI(x, ...) ALOGI("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define CB_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define CB_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__) namespace android { @@ -86,8 +86,10 @@ ConsumerBase::~ConsumerBase() { // be done by ConsumerBase::onLastStrongRef(), but it's possible for a // derived class to override that method and not call // ConsumerBase::onLastStrongRef(). - LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~ConsumerBase was called, but the " - "consumer is not abandoned!", mName.string()); + LOG_ALWAYS_FATAL_IF(!mAbandoned, + "[%s] ~ConsumerBase was called, but the " + "consumer is not abandoned!", + mName.c_str()); } void ConsumerBase::onLastStrongRef(const void* id __attribute__((unused))) { @@ -451,7 +453,7 @@ status_t ConsumerBase::addReleaseFenceLocked(int slot, // them to get an accurate timestamp. if (currentStatus == incomingStatus) { char fenceName[32] = {}; - snprintf(fenceName, 32, "%.28s:%d", mName.string(), slot); + snprintf(fenceName, 32, "%.28s:%d", mName.c_str(), slot); sp mergedFence = Fence::merge( fenceName, mSlots[slot].mFence, fence); if (!mergedFence.get()) { diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp index a62697064b..3031fa11fc 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -23,11 +23,11 @@ #include #include -#define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define CC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define CC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) -#define CC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) -#define CC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) +#define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define CC_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define CC_LOGI(x, ...) ALOGI("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define CC_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define CC_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__) namespace android { diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index b3647d6126..d49489c5a8 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -52,11 +52,11 @@ namespace android { // Macros for including the GLConsumer name in log messages -#define GLC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) -#define GLC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define GLC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) -#define GLC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) -#define GLC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) +#define GLC_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define GLC_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__) +// #define GLC_LOGI(x, ...) ALOGI("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define GLC_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define GLC_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__) static const struct { uint32_t width, height; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 78401205ff..dd1fad0f6b 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1275,7 +1275,7 @@ sp SurfaceComposerClient::createDisplay(const String8& displayName, boo sp display = nullptr; binder::Status status = ComposerServiceAIDL::getComposerService()->createDisplay(std::string( - displayName.string()), + displayName.c_str()), secure, requestedRefereshRate, &display); return status.isOk() ? display : nullptr; diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index 8d0828d88e..22c2be7bc7 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -34,13 +34,13 @@ #include #include -#define ATRACE_BUFFER_INDEX(index) \ - do { \ - if (ATRACE_ENABLED()) { \ - char ___traceBuf[1024]; \ - snprintf(___traceBuf, 1024, "%s: %d", mCore->mConsumerName.string(), (index)); \ - android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf); \ - } \ +#define ATRACE_BUFFER_INDEX(index) \ + do { \ + if (ATRACE_ENABLED()) { \ + char ___traceBuf[1024]; \ + snprintf(___traceBuf, 1024, "%s: %d", mCore->mConsumerName.c_str(), (index)); \ + android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf); \ + } \ } while (false) namespace android { diff --git a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h index 004d87574a..32dc88ba84 100644 --- a/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h +++ b/libs/gui/include/gui/bufferqueue/1.0/WGraphicBufferProducer.h @@ -298,7 +298,7 @@ struct TWGraphicBufferProducer : public BASE { } Return getConsumerName(HGraphicBufferProducer::getConsumerName_cb _hidl_cb) override { - _hidl_cb(mBase->getConsumerName().string()); + _hidl_cb(mBase->getConsumerName().c_str()); return Void(); } diff --git a/libs/gui/tests/GLTest.cpp b/libs/gui/tests/GLTest.cpp index afeea42546..ae79e5bace 100644 --- a/libs/gui/tests/GLTest.cpp +++ b/libs/gui/tests/GLTest.cpp @@ -177,7 +177,7 @@ EGLSurface GLTest::createWindowSurface(EGLDisplay display, EGLConfig config, while ((err = glGetError()) != GL_NO_ERROR) { msg += String8::format(", %#x", err); } - return ::testing::AssertionFailure(::testing::Message(msg.string())); + return ::testing::AssertionFailure(::testing::Message(msg.c_str())); } if (r >= 0 && abs(r - int(pixel[0])) > tolerance) { msg += String8::format("r(%d isn't %d)", pixel[0], r); @@ -201,7 +201,7 @@ EGLSurface GLTest::createWindowSurface(EGLDisplay display, EGLConfig config, msg += String8::format("a(%d isn't %d)", pixel[3], a); } if (!msg.isEmpty()) { - return ::testing::AssertionFailure(::testing::Message(msg.string())); + return ::testing::AssertionFailure(::testing::Message(msg.c_str())); } else { return ::testing::AssertionSuccess(); } @@ -236,8 +236,8 @@ EGLSurface GLTest::createWindowSurface(EGLDisplay display, EGLConfig config, msg += String8::format(" R1: [%d %d %d %d] R2: [%d %d %d %d]", r1.left, r1.top, r1.right, r1.bottom, r2.left, r2.top, r2.right, r2.bottom); - fprintf(stderr, "assertRectEq: %s\n", msg.string()); - return ::testing::AssertionFailure(::testing::Message(msg.string())); + fprintf(stderr, "assertRectEq: %s\n", msg.c_str()); + return ::testing::AssertionFailure(::testing::Message(msg.c_str())); } else { return ::testing::AssertionSuccess(); } diff --git a/libs/gui/tests/SurfaceTextureFBO_test.cpp b/libs/gui/tests/SurfaceTextureFBO_test.cpp index f34561f668..ccd0e59616 100644 --- a/libs/gui/tests/SurfaceTextureFBO_test.cpp +++ b/libs/gui/tests/SurfaceTextureFBO_test.cpp @@ -59,7 +59,7 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) { glBindFramebuffer(GL_FRAMEBUFFER, 0); for (int i = 0; i < 4; i++) { - SCOPED_TRACE(String8::format("frame %d", i).string()); + SCOPED_TRACE(String8::format("frame %d", i).c_str()); ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp index e2b4f3d035..f76c0be265 100644 --- a/libs/gui/tests/SurfaceTextureGL_test.cpp +++ b/libs/gui/tests/SurfaceTextureGL_test.cpp @@ -147,8 +147,9 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) { for (int i = 0; i < 5; i++) { const android_native_rect_t& crop(crops[i]); - SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }", - crop.left, crop.top, crop.right, crop.bottom).string()); + SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }", crop.left, crop.top, + crop.right, crop.bottom) + .c_str()); ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop)); @@ -308,7 +309,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) { mFW->waitForFrame(); for (int i = 0; i < numFrames; i++) { - SCOPED_TRACE(String8::format("frame %d", i).string()); + SCOPED_TRACE(String8::format("frame %d", i).c_str()); // We must wait for each frame to come in because if we ever do an // updateTexImage call that doesn't consume a newly available buffer diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 30b7a9fb54..e89998ff3d 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -415,7 +415,7 @@ TEST_F(SurfaceTest, GetConsumerName) { sp window(surface); native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); - EXPECT_STREQ("TestConsumer", surface->getConsumerName().string()); + EXPECT_STREQ("TestConsumer", surface->getConsumerName().c_str()); } TEST_F(SurfaceTest, GetWideColorSupport) { diff --git a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp index 0128859ca6..275b7a4888 100644 --- a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp +++ b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp @@ -38,10 +38,10 @@ namespace android { // Macros for including the SurfaceTexture name in log messages -#define EGC_LOGV(x, ...) ALOGV("[%s] " x, st.mName.string(), ##__VA_ARGS__) -#define EGC_LOGD(x, ...) ALOGD("[%s] " x, st.mName.string(), ##__VA_ARGS__) -#define EGC_LOGW(x, ...) ALOGW("[%s] " x, st.mName.string(), ##__VA_ARGS__) -#define EGC_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__) +#define EGC_LOGV(x, ...) ALOGV("[%s] " x, st.mName.c_str(), ##__VA_ARGS__) +#define EGC_LOGD(x, ...) ALOGD("[%s] " x, st.mName.c_str(), ##__VA_ARGS__) +#define EGC_LOGW(x, ...) ALOGW("[%s] " x, st.mName.c_str(), ##__VA_ARGS__) +#define EGC_LOGE(x, ...) ALOGE("[%s] " x, st.mName.c_str(), ##__VA_ARGS__) static const struct { uint32_t width, height; diff --git a/libs/nativedisplay/surfacetexture/ImageConsumer.cpp b/libs/nativedisplay/surfacetexture/ImageConsumer.cpp index cf16739e89..32b229d77c 100644 --- a/libs/nativedisplay/surfacetexture/ImageConsumer.cpp +++ b/libs/nativedisplay/surfacetexture/ImageConsumer.cpp @@ -19,7 +19,7 @@ #include // Macro for including the SurfaceTexture name in log messages -#define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__) +#define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.c_str(), ##__VA_ARGS__) namespace android { diff --git a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp index d3d4cbafdf..9f610e1a50 100644 --- a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp +++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp @@ -26,10 +26,10 @@ namespace android { // Macros for including the SurfaceTexture name in log messages -#define SFT_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) -#define SFT_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) -#define SFT_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) -#define SFT_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) +#define SFT_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define SFT_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define SFT_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__) +#define SFT_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__) static const mat4 mtxIdentity; diff --git a/libs/renderengine/skia/GLExtensions.cpp b/libs/renderengine/skia/GLExtensions.cpp index 32da303a92..1d4d35fb54 100644 --- a/libs/renderengine/skia/GLExtensions.cpp +++ b/libs/renderengine/skia/GLExtensions.cpp @@ -68,19 +68,19 @@ void GLExtensions::initWithGLStrings(GLubyte const* vendor, GLubyte const* rende } char const* GLExtensions::getVendor() const { - return mVendor.string(); + return mVendor.c_str(); } char const* GLExtensions::getRenderer() const { - return mRenderer.string(); + return mRenderer.c_str(); } char const* GLExtensions::getVersion() const { - return mVersion.string(); + return mVersion.c_str(); } char const* GLExtensions::getExtensions() const { - return mExtensions.string(); + return mExtensions.c_str(); } void GLExtensions::initWithEGLStrings(char const* eglVersion, char const* eglExtensions) { @@ -127,11 +127,11 @@ void GLExtensions::initWithEGLStrings(char const* eglVersion, char const* eglExt } char const* GLExtensions::getEGLVersion() const { - return mEGLVersion.string(); + return mEGLVersion.c_str(); } char const* GLExtensions::getEGLExtensions() const { - return mEGLExtensions.string(); + return mEGLExtensions.c_str(); } } // namespace skia diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp index cc96f83578..4be0a3a9d9 100644 --- a/libs/ui/Fence.cpp +++ b/libs/ui/Fence.cpp @@ -115,7 +115,7 @@ sp Fence::merge(const char* name, const sp& f1, sp Fence::merge(const String8& name, const sp& f1, const sp& f2) { - return merge(name.string(), f1, f2); + return merge(name.c_str(), f1, f2); } int Fence::dup() const { diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 4a08c11c14..48d793a4d4 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -143,7 +143,7 @@ status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector= 1) { if (args[0] == String16("vkjson")) return cmdVkjson(out, err); diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp index f439caf9e1..8dab6ce61b 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp @@ -34,7 +34,7 @@ LayerState::LayerState(compositionengine::OutputLayer* layer) [](const mat4& mat) { using namespace std::string_literals; std::vector split = - base::Split(std::string(mat.asString().string()), "\n"s); + base::Split(std::string(mat.asString().c_str()), "\n"s); split.pop_back(); // Strip the last (empty) line return split; }}) { diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp index 54133d92b0..5e6cade56f 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp @@ -216,32 +216,32 @@ void Planner::dump(const Vector& args, std::string& result) { base::StringAppendF(&result, "Expected two layer stack hashes, e.g. '--planner %s " " '\n", - command.string()); + command.c_str()); return; } if (args.size() > 4) { base::StringAppendF(&result, "Too many arguments found, expected '--planner %s " "'\n", - command.string()); + command.c_str()); return; } const String8 leftHashString(args[2]); size_t leftHash = 0; - int fieldsRead = sscanf(leftHashString.string(), "%zx", &leftHash); + int fieldsRead = sscanf(leftHashString.c_str(), "%zx", &leftHash); if (fieldsRead != 1) { base::StringAppendF(&result, "Failed to parse %s as a size_t\n", - leftHashString.string()); + leftHashString.c_str()); return; } const String8 rightHashString(args[3]); size_t rightHash = 0; - fieldsRead = sscanf(rightHashString.string(), "%zx", &rightHash); + fieldsRead = sscanf(rightHashString.c_str(), "%zx", &rightHash); if (fieldsRead != 1) { base::StringAppendF(&result, "Failed to parse %s as a size_t\n", - rightHashString.string()); + rightHashString.c_str()); return; } @@ -252,22 +252,22 @@ void Planner::dump(const Vector& args, std::string& result) { if (args.size() < 3) { base::StringAppendF(&result, "Expected a layer stack hash, e.g. '--planner %s '\n", - command.string()); + command.c_str()); return; } if (args.size() > 3) { base::StringAppendF(&result, "Too many arguments found, expected '--planner %s '\n", - command.string()); + command.c_str()); return; } const String8 hashString(args[2]); size_t hash = 0; - const int fieldsRead = sscanf(hashString.string(), "%zx", &hash); + const int fieldsRead = sscanf(hashString.c_str(), "%zx", &hash); if (fieldsRead != 1) { base::StringAppendF(&result, "Failed to parse %s as a size_t\n", - hashString.string()); + hashString.c_str()); return; } @@ -279,20 +279,20 @@ void Planner::dump(const Vector& args, std::string& result) { } else if (command == "--similar" || command == "-s") { if (args.size() < 3) { base::StringAppendF(&result, "Expected a plan string, e.g. '--planner %s '\n", - command.string()); + command.c_str()); return; } if (args.size() > 3) { base::StringAppendF(&result, "Too many arguments found, expected '--planner %s '\n", - command.string()); + command.c_str()); return; } const String8 planString(args[2]); - std::optional plan = Plan::fromString(std::string(planString.string())); + std::optional plan = Plan::fromString(std::string(planString.c_str())); if (!plan) { - base::StringAppendF(&result, "Failed to parse %s as a Plan\n", planString.string()); + base::StringAppendF(&result, "Failed to parse %s as a Plan\n", planString.c_str()); return; } @@ -302,7 +302,7 @@ void Planner::dump(const Vector& args, std::string& result) { } else if (command == "--layers" || command == "-l") { mFlattener.dumpLayers(result); } else { - base::StringAppendF(&result, "Unknown command '%s'\n\n", command.string()); + base::StringAppendF(&result, "Unknown command '%s'\n\n", command.c_str()); dumpUsage(result); } return; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d787a55e29..4a201ee2e1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5926,7 +5926,7 @@ void SurfaceFlinger::dumpStatsLocked(const DumpArgs& args, std::string& result) const auto name = String8(args[1]); mCurrentState.traverseInZOrder([&](Layer* layer) { - if (layer->getName() == name.string()) { + if (layer->getName() == name.c_str()) { layer->dumpFrameStats(result); } }); @@ -5937,7 +5937,7 @@ void SurfaceFlinger::clearStatsLocked(const DumpArgs& args, std::string&) { const auto name = clearAll ? String8() : String8(args[1]); mCurrentState.traverse([&](Layer* layer) { - if (clearAll || layer->getName() == name.string()) { + if (clearAll || layer->getName() == name.c_str()) { layer->clearFrameStats(); } }); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp index 1cc9ba40bd..dbf0cd8772 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp @@ -91,7 +91,7 @@ TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForNonsecureDisplay) { const auto& display = getCurrentDisplayState(displayToken); EXPECT_TRUE(display.isVirtual()); EXPECT_FALSE(display.isSecure); - EXPECT_EQ(name.string(), display.displayName); + EXPECT_EQ(name.c_str(), display.displayName); // -------------------------------------------------------------------- // Cleanup conditions @@ -123,7 +123,7 @@ TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForSecureDisplay) { const auto& display = getCurrentDisplayState(displayToken); EXPECT_TRUE(display.isVirtual()); EXPECT_TRUE(display.isSecure); - EXPECT_EQ(name.string(), display.displayName); + EXPECT_EQ(name.c_str(), display.displayName); // -------------------------------------------------------------------- // Cleanup conditions diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h index f297da5511..1675584f5a 100644 --- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h +++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h @@ -170,7 +170,7 @@ public: String8 err(String8::format("pixel @ (%3d, %3d): " "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]", x, y, r, g, b, pixel[0], pixel[1], pixel[2])); - EXPECT_EQ(String8(), err) << err.string(); + EXPECT_EQ(String8(), err) << err.c_str(); } } -- cgit v1.2.3-59-g8ed1b From ce6e0044cfea1e0ee38a48714364940a9de3e49a Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Tue, 27 Jun 2023 11:22:54 -0700 Subject: Add setFrameRateCategory surface API Bug: 284911776 Test: atest CtsSurfaceControlTestsStaging Test: atest libsurfaceflinger_unittest Change-Id: Ia804a63198ff096d1e5ffedf6046a0350963b8ed --- libs/gui/LayerState.cpp | 8 + libs/gui/SurfaceComposerClient.cpp | 12 ++ libs/gui/include/gui/LayerState.h | 6 +- libs/gui/include/gui/SurfaceComposerClient.h | 2 + libs/nativewindow/include/system/window.h | 36 ++++ .../FrontEnd/LayerSnapshotBuilder.cpp | 24 ++- .../FrontEnd/RequestedLayerState.cpp | 13 +- services/surfaceflinger/Layer.cpp | 100 +++++------ services/surfaceflinger/Layer.h | 3 +- services/surfaceflinger/Scheduler/LayerHistory.cpp | 58 ++++--- services/surfaceflinger/Scheduler/LayerInfo.cpp | 98 ++++++++++- services/surfaceflinger/Scheduler/LayerInfo.h | 60 +++++-- .../Scheduler/RefreshRateSelector.cpp | 102 +++++++++--- .../surfaceflinger/Scheduler/RefreshRateSelector.h | 23 ++- .../Scheduler/include/scheduler/Fps.h | 12 ++ services/surfaceflinger/SurfaceFlinger.cpp | 12 +- .../tests/unittests/LayerHierarchyTest.h | 11 ++ .../tests/unittests/LayerHistoryTest.cpp | 111 +++++++++++++ .../tests/unittests/LayerInfoTest.cpp | 78 +++++++++ .../tests/unittests/LayerSnapshotTest.cpp | 184 ++++++++++++++++----- .../tests/unittests/RefreshRateSelectorTest.cpp | 115 +++++++++++++ .../tests/unittests/SetFrameRateTest.cpp | 56 +++---- 22 files changed, 905 insertions(+), 219 deletions(-) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 2322b70d1c..e1afb524e7 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -83,6 +83,7 @@ layer_state_t::layer_state_t() frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), changeFrameRateStrategy(ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS), defaultFrameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), + frameRateCategory(ANATIVEWINDOW_FRAME_RATE_CATEGORY_DEFAULT), fixedTransformHint(ui::Transform::ROT_INVALID), autoRefresh(false), isTrustedOverlay(false), @@ -158,6 +159,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeByte, frameRateCompatibility); SAFE_PARCEL(output.writeByte, changeFrameRateStrategy); SAFE_PARCEL(output.writeByte, defaultFrameRateCompatibility); + SAFE_PARCEL(output.writeByte, frameRateCategory); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeBool, autoRefresh); SAFE_PARCEL(output.writeBool, dimmingEnabled); @@ -290,6 +292,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readByte, &frameRateCompatibility); SAFE_PARCEL(input.readByte, &changeFrameRateStrategy); SAFE_PARCEL(input.readByte, &defaultFrameRateCompatibility); + SAFE_PARCEL(input.readByte, &frameRateCategory); SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); SAFE_PARCEL(input.readBool, &autoRefresh); @@ -659,6 +662,10 @@ void layer_state_t::merge(const layer_state_t& other) { frameRateCompatibility = other.frameRateCompatibility; changeFrameRateStrategy = other.changeFrameRateStrategy; } + if (other.what & eFrameRateCategoryChanged) { + what |= eFrameRateCategoryChanged; + frameRateCategory = other.frameRateCategory; + } if (other.what & eFixedTransformHintChanged) { what |= eFixedTransformHintChanged; fixedTransformHint = other.fixedTransformHint; @@ -769,6 +776,7 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const { CHECK_DIFF(diff, eFrameRateSelectionPriority, other, frameRateSelectionPriority); CHECK_DIFF3(diff, eFrameRateChanged, other, frameRate, frameRateCompatibility, changeFrameRateStrategy); + CHECK_DIFF(diff, eFrameRateCategoryChanged, other, frameRateCategory); CHECK_DIFF(diff, eFixedTransformHintChanged, other, fixedTransformHint); CHECK_DIFF(diff, eAutoRefreshChanged, other, autoRefresh); CHECK_DIFF(diff, eTrustedOverlayChanged, other, isTrustedOverlay); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 78401205ff..dc35c1c60e 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2092,6 +2092,18 @@ SurfaceComposerClient::Transaction::setDefaultFrameRateCompatibility(const sp& sc, int8_t category) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eFrameRateCategoryChanged; + s->frameRateCategory = category; + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixedTransformHint( const sp& sc, int32_t fixedTransformHint) { layer_state_t* s = getLayerState(sc); diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 7aa7068538..03d52d27b5 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -181,7 +181,7 @@ struct layer_state_t { eRelativeLayerChanged = 0x00004000, eReparent = 0x00008000, eColorChanged = 0x00010000, - /* unused = 0x00020000, */ + eFrameRateCategoryChanged = 0x00020000, eBufferTransformChanged = 0x00040000, eTransformToDisplayInverseChanged = 0x00080000, eCropChanged = 0x00100000, @@ -213,7 +213,6 @@ struct layer_state_t { eTrustedOverlayChanged = 0x4000'00000000, eDropInputModeChanged = 0x8000'00000000, eExtendedRangeBrightnessChanged = 0x10000'00000000, - }; layer_state_t(); @@ -358,6 +357,9 @@ struct layer_state_t { // Default frame rate compatibility used to set the layer refresh rate votetype. int8_t defaultFrameRateCompatibility; + // Frame rate category to suggest what frame rate range a surface should run. + int8_t frameRateCategory; + // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that // the graphic producers should receive a transform hint as if the diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index dbcbd3bd62..fd9f186663 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -675,6 +675,8 @@ public: Transaction& setDefaultFrameRateCompatibility(const sp& sc, int8_t compatibility); + Transaction& setFrameRateCategory(const sp& sc, int8_t category); + // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that // the graphic producers should receive a transform hint as if the diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index edaa422e55..e158f01e8c 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1060,6 +1060,42 @@ enum { ANATIVEWINDOW_FRAME_RATE_MIN }; +/* + * Frame rate category values that can be used in Transaction::setFrameRateCategory. + */ +enum { + /** + * Default value. This value can also be set to return to default behavior, such as layers + * without animations. + */ + ANATIVEWINDOW_FRAME_RATE_CATEGORY_DEFAULT = 0, + + /** + * The layer will explicitly not influence the frame rate. + * This may indicate a frame rate suitable for no animation updates (such as a cursor blinking + * or a sporadic update). + */ + ANATIVEWINDOW_FRAME_RATE_CATEGORY_NO_PREFERENCE = 1, + + /** + * Indicates a frame rate suitable for animations that looks fine even if played at a low frame + * rate. + */ + ANATIVEWINDOW_FRAME_RATE_CATEGORY_LOW = 2, + + /** + * Indicates a middle frame rate suitable for animations that do not require higher frame + * rates, or do not benefit from high smoothness. This is normally 60 Hz or close to it. + */ + ANATIVEWINDOW_FRAME_RATE_CATEGORY_NORMAL = 3, + + /** + * Indicates a frame rate suitable for animations that require a high frame rate, which may + * increase smoothness but may also increase power usage. + */ + ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH = 4 +}; + static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) { return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate, diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 159d0f028d..758c46853d 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -675,8 +675,7 @@ void LayerSnapshotBuilder::updateFrameRateFromChildSnapshot(LayerSnapshot& snaps } using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility; - if (snapshot.frameRate.rate.isValid() || - snapshot.frameRate.type == FrameRateCompatibility::NoVote) { + if (snapshot.frameRate.isValid()) { // we already have a valid framerate. return; } @@ -684,15 +683,17 @@ void LayerSnapshotBuilder::updateFrameRateFromChildSnapshot(LayerSnapshot& snaps // We return whether this layer or its children has a vote. We ignore ExactOrMultiple votes // for the same reason we are allowing touch boost for those layers. See // RefreshRateSelector::rankFrameRates for details. - const auto layerVotedWithDefaultCompatibility = childSnapshot.frameRate.rate.isValid() && - childSnapshot.frameRate.type == FrameRateCompatibility::Default; + const auto layerVotedWithDefaultCompatibility = childSnapshot.frameRate.vote.rate.isValid() && + childSnapshot.frameRate.vote.type == FrameRateCompatibility::Default; const auto layerVotedWithNoVote = - childSnapshot.frameRate.type == FrameRateCompatibility::NoVote; - const auto layerVotedWithExactCompatibility = childSnapshot.frameRate.rate.isValid() && - childSnapshot.frameRate.type == FrameRateCompatibility::Exact; + childSnapshot.frameRate.vote.type == FrameRateCompatibility::NoVote; + const auto layerVotedWithCategory = + childSnapshot.frameRate.category != FrameRateCategory::Default; + const auto layerVotedWithExactCompatibility = childSnapshot.frameRate.vote.rate.isValid() && + childSnapshot.frameRate.vote.type == FrameRateCompatibility::Exact; bool childHasValidFrameRate = layerVotedWithDefaultCompatibility || layerVotedWithNoVote || - layerVotedWithExactCompatibility; + layerVotedWithCategory || layerVotedWithExactCompatibility; // If we don't have a valid frame rate, but the children do, we set this // layer as NoVote to allow the children to control the refresh rate @@ -820,11 +821,8 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a RequestedLayerState::Changes::Hierarchy) || snapshot.changes.any(RequestedLayerState::Changes::FrameRate | RequestedLayerState::Changes::Hierarchy)) { - snapshot.frameRate = (requested.requestedFrameRate.rate.isValid() || - (requested.requestedFrameRate.type == - scheduler::LayerInfo::FrameRateCompatibility::NoVote)) - ? requested.requestedFrameRate - : parentSnapshot.frameRate; + snapshot.frameRate = requested.requestedFrameRate.isValid() ? requested.requestedFrameRate + : parentSnapshot.frameRate; snapshot.changes |= RequestedLayerState::Changes::FrameRate; } diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index d979c4662e..43800e279f 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -24,6 +24,8 @@ #include #include +#include + #include "Layer.h" #include "LayerCreationArgs.h" #include "LayerLog.h" @@ -123,6 +125,7 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) dimmingEnabled = true; defaultFrameRateCompatibility = static_cast(scheduler::LayerInfo::FrameRateCompatibility::Default); + frameRateCategory = static_cast(FrameRateCategory::Default); dataspace = ui::Dataspace::V0_SRGB; gameMode = gui::GameMode::Unsupported; requestedFrameRate = {}; @@ -319,8 +322,14 @@ void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerSta Layer::FrameRate::convertCompatibility(clientState.frameRateCompatibility); const auto strategy = Layer::FrameRate::convertChangeFrameRateStrategy( clientState.changeFrameRateStrategy); - requestedFrameRate = - Layer::FrameRate(Fps::fromValue(clientState.frameRate), compatibility, strategy); + requestedFrameRate.vote = + Layer::FrameRate::FrameRateVote(Fps::fromValue(clientState.frameRate), + compatibility, strategy); + changes |= RequestedLayerState::Changes::FrameRate; + } + if (clientState.what & layer_state_t::eFrameRateCategoryChanged) { + const auto category = Layer::FrameRate::convertCategory(clientState.frameRateCategory); + requestedFrameRate.category = category; changes |= RequestedLayerState::Changes::FrameRate; } } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 59a8825de5..95e1a2f0d3 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -27,7 +27,6 @@ #include #include -#include #include #include #include @@ -101,7 +100,7 @@ TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility; using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness; const auto frameRateCompatibility = [frameRate] { - switch (frameRate.type) { + switch (frameRate.vote.type) { case Layer::FrameRateCompatibility::Default: return FrameRateCompatibility::Default; case Layer::FrameRateCompatibility::ExactOrMultiple: @@ -112,7 +111,7 @@ TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate }(); const auto seamlessness = [frameRate] { - switch (frameRate.seamlessness) { + switch (frameRate.vote.seamlessness) { case scheduler::Seamlessness::OnlySeamless: return Seamlessness::ShouldBeSeamless; case scheduler::Seamlessness::SeamedAndSeamless: @@ -122,7 +121,7 @@ TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate } }(); - return TimeStats::SetFrameRateVote{.frameRate = frameRate.rate.getValue(), + return TimeStats::SetFrameRateVote{.frameRate = frameRate.vote.rate.getValue(), .frameRateCompatibility = frameRateCompatibility, .seamlessness = seamlessness}; } @@ -1264,8 +1263,7 @@ const half4& Layer::getBorderColor() { bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* transactionNeeded) { // The frame rate for layer tree is this layer's frame rate if present, or the parent frame rate const auto frameRate = [&] { - if (mDrawingState.frameRate.rate.isValid() || - mDrawingState.frameRate.type == FrameRateCompatibility::NoVote) { + if (mDrawingState.frameRate.isValid()) { return mDrawingState.frameRate; } @@ -1281,23 +1279,23 @@ bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* tran child->propagateFrameRateForLayerTree(frameRate, transactionNeeded); } - // If we don't have a valid frame rate, but the children do, we set this + // If we don't have a valid frame rate specification, but the children do, we set this // layer as NoVote to allow the children to control the refresh rate - if (!frameRate.rate.isValid() && frameRate.type != FrameRateCompatibility::NoVote && - childrenHaveFrameRate) { + if (!frameRate.isValid() && childrenHaveFrameRate) { *transactionNeeded |= setFrameRateForLayerTreeLegacy(FrameRate(Fps(), FrameRateCompatibility::NoVote)); } - // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes for + // We return whether this layer or its children has a vote. We ignore ExactOrMultiple votes for // the same reason we are allowing touch boost for those layers. See // RefreshRateSelector::rankFrameRates for details. const auto layerVotedWithDefaultCompatibility = - frameRate.rate.isValid() && frameRate.type == FrameRateCompatibility::Default; - const auto layerVotedWithNoVote = frameRate.type == FrameRateCompatibility::NoVote; + frameRate.vote.rate.isValid() && frameRate.vote.type == FrameRateCompatibility::Default; + const auto layerVotedWithNoVote = frameRate.vote.type == FrameRateCompatibility::NoVote; + const auto layerVotedWithCategory = frameRate.category != FrameRateCategory::Default; const auto layerVotedWithExactCompatibility = - frameRate.rate.isValid() && frameRate.type == FrameRateCompatibility::Exact; - return layerVotedWithDefaultCompatibility || layerVotedWithNoVote || + frameRate.vote.rate.isValid() && frameRate.vote.type == FrameRateCompatibility::Exact; + return layerVotedWithDefaultCompatibility || layerVotedWithNoVote || layerVotedWithCategory || layerVotedWithExactCompatibility || childrenHaveFrameRate; } @@ -1319,13 +1317,28 @@ void Layer::updateTreeHasFrameRateVote() { } } -bool Layer::setFrameRate(FrameRate frameRate) { - if (mDrawingState.frameRate == frameRate) { +bool Layer::setFrameRate(FrameRate::FrameRateVote frameRateVote) { + if (mDrawingState.frameRate.vote == frameRateVote) { return false; } mDrawingState.sequence++; - mDrawingState.frameRate = frameRate; + mDrawingState.frameRate.vote = frameRateVote; + mDrawingState.modified = true; + + updateTreeHasFrameRateVote(); + + setTransactionFlags(eTransactionNeeded); + return true; +} + +bool Layer::setFrameRateCategory(FrameRateCategory category) { + if (mDrawingState.frameRate.category == category) { + return false; + } + + mDrawingState.sequence++; + mDrawingState.frameRate.category = category; mDrawingState.modified = true; updateTreeHasFrameRateVote(); @@ -1651,10 +1664,10 @@ void Layer::miniDumpLegacy(std::string& result, const DisplayDevice& display) co StringAppendF(&result, "%6.1f %6.1f %6.1f %6.1f | ", crop.left, crop.top, crop.right, crop.bottom); const auto frameRate = getFrameRateForLayerTree(); - if (frameRate.rate.isValid() || frameRate.type != FrameRateCompatibility::Default) { - StringAppendF(&result, "%s %15s %17s", to_string(frameRate.rate).c_str(), - ftl::enum_string(frameRate.type).c_str(), - ftl::enum_string(frameRate.seamlessness).c_str()); + if (frameRate.vote.rate.isValid() || frameRate.vote.type != FrameRateCompatibility::Default) { + StringAppendF(&result, "%s %15s %17s", to_string(frameRate.vote.rate).c_str(), + ftl::enum_string(frameRate.vote.type).c_str(), + ftl::enum_string(frameRate.vote.seamlessness).c_str()); } else { result.append(41, ' '); } @@ -1686,10 +1699,10 @@ void Layer::miniDump(std::string& result, const frontend::LayerSnapshot& snapsho StringAppendF(&result, "%6.1f %6.1f %6.1f %6.1f | ", crop.left, crop.top, crop.right, crop.bottom); const auto frameRate = snapshot.frameRate; - if (frameRate.rate.isValid() || frameRate.type != FrameRateCompatibility::Default) { - StringAppendF(&result, "%s %15s %17s", to_string(frameRate.rate).c_str(), - ftl::enum_string(frameRate.type).c_str(), - ftl::enum_string(frameRate.seamlessness).c_str()); + if (frameRate.vote.rate.isValid() || frameRate.vote.type != FrameRateCompatibility::Default) { + StringAppendF(&result, "%s %15s %17s", to_string(frameRate.vote.rate).c_str(), + ftl::enum_string(frameRate.vote.type).c_str(), + ftl::enum_string(frameRate.vote.seamlessness).c_str()); } else { result.append(41, ' '); } @@ -2823,36 +2836,6 @@ void Layer::addChildToDrawing(const sp& layer) { layer->mDrawingParent = sp::fromExisting(this); } -Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t compatibility) { - switch (compatibility) { - case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT: - return FrameRateCompatibility::Default; - case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE: - return FrameRateCompatibility::ExactOrMultiple; - case ANATIVEWINDOW_FRAME_RATE_EXACT: - return FrameRateCompatibility::Exact; - case ANATIVEWINDOW_FRAME_RATE_MIN: - return FrameRateCompatibility::Min; - case ANATIVEWINDOW_FRAME_RATE_NO_VOTE: - return FrameRateCompatibility::NoVote; - default: - LOG_ALWAYS_FATAL("Invalid frame rate compatibility value %d", compatibility); - return FrameRateCompatibility::Default; - } -} - -scheduler::Seamlessness Layer::FrameRate::convertChangeFrameRateStrategy(int8_t strategy) { - switch (strategy) { - case ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS: - return Seamlessness::OnlySeamless; - case ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS: - return Seamlessness::SeamedAndSeamless; - default: - LOG_ALWAYS_FATAL("Invalid change frame sate strategy value %d", strategy); - return Seamlessness::Default; - } -} - bool Layer::isInternalDisplayOverlay() const { const State& s(mDrawingState); if (s.flags & layer_state_t::eLayerSkipScreenshot) { @@ -4366,13 +4349,6 @@ void Layer::updateLastLatchTime(nsecs_t latchTime) { mLastLatchTime = latchTime; } -// --------------------------------------------------------------------------- - -std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { - return stream << "{rate=" << rate.rate << " type=" << ftl::enum_string(rate.type) - << " seamlessness=" << ftl::enum_string(rate.seamlessness) << '}'; -} - } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index d1912e4c9c..568e4c49dd 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -778,7 +778,8 @@ public: */ Rect getCroppedBufferSize(const Layer::State& s) const; - bool setFrameRate(FrameRate); + bool setFrameRate(FrameRate::FrameRateVote); + bool setFrameRateCategory(FrameRateCategory); virtual void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {} void setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info, nsecs_t postTime); diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 5d00a26031..565a490ec8 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -40,8 +40,9 @@ namespace android::scheduler { namespace { bool isLayerActive(const LayerInfo& info, nsecs_t threshold) { - // Layers with an explicit vote are always kept active - if (info.getSetFrameRateVote().rate.isValid()) { + // Layers with an explicit frame rate or frame rate category are always kept active, + // but ignore NoVote/NoPreference. + if (info.getSetFrameRateVote().isValid() && !info.getSetFrameRateVote().isNoVote()) { return true; } @@ -70,6 +71,7 @@ void trace(const LayerInfo& info, LayerHistory::LayerVoteType type, int fps) { traceType(LayerHistory::LayerVoteType::ExplicitExact, fps); traceType(LayerHistory::LayerVoteType::Min, 1); traceType(LayerHistory::LayerVoteType::Max, 1); + traceType(LayerHistory::LayerVoteType::ExplicitCategory, 1); ALOGD("%s: %s @ %d Hz", __FUNCTION__, info.getName().c_str(), fps); } @@ -171,27 +173,32 @@ auto LayerHistory::summarize(const RefreshRateSelector& selector, nsecs_t now) - layerFocused ? "" : "not"); ATRACE_FORMAT("%s", info->getName().c_str()); - const auto vote = info->getRefreshRateVote(selector, now); - // Skip NoVote layer as those don't have any requirements - if (vote.type == LayerVoteType::NoVote) { - continue; - } + const auto votes = info->getRefreshRateVote(selector, now); + for (LayerInfo::LayerVote vote : votes) { + if (vote.isNoVote()) { + continue; + } + + // Compute the layer's position on the screen + const Rect bounds = Rect(info->getBounds()); + const ui::Transform transform = info->getTransform(); + constexpr bool roundOutwards = true; + Rect transformed = transform.transform(bounds, roundOutwards); + + const float layerArea = transformed.getWidth() * transformed.getHeight(); + float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f; + const std::string categoryString = vote.category == FrameRateCategory::Default + ? base::StringPrintf("category=%s", ftl::enum_string(vote.category).c_str()) + : ""; + ATRACE_FORMAT_INSTANT("%s %s %s (%d%)", ftl::enum_string(vote.type).c_str(), + to_string(vote.fps).c_str(), categoryString.c_str(), + weight * 100); + summary.push_back({info->getName(), info->getOwnerUid(), vote.type, vote.fps, + vote.seamlessness, vote.category, weight, layerFocused}); - // Compute the layer's position on the screen - const Rect bounds = Rect(info->getBounds()); - const ui::Transform transform = info->getTransform(); - constexpr bool roundOutwards = true; - Rect transformed = transform.transform(bounds, roundOutwards); - - const float layerArea = transformed.getWidth() * transformed.getHeight(); - float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f; - ATRACE_FORMAT_INSTANT("%s %s (%d%)", ftl::enum_string(vote.type).c_str(), - to_string(vote.fps).c_str(), weight * 100); - summary.push_back({info->getName(), info->getOwnerUid(), vote.type, vote.fps, - vote.seamlessness, weight, layerFocused}); - - if (CC_UNLIKELY(mTraceEnabled)) { - trace(*info, vote.type, vote.fps.getIntValue()); + if (CC_UNLIKELY(mTraceEnabled)) { + trace(*info, vote.type, vote.fps.getIntValue()); + } } } @@ -228,7 +235,7 @@ void LayerHistory::partitionLayers(nsecs_t now) { // Set layer vote if set const auto frameRate = info->getSetFrameRateVote(); const auto voteType = [&]() { - switch (frameRate.type) { + switch (frameRate.vote.type) { case Layer::FrameRateCompatibility::Default: return LayerVoteType::ExplicitDefault; case Layer::FrameRateCompatibility::Min: @@ -242,9 +249,10 @@ void LayerHistory::partitionLayers(nsecs_t now) { } }(); - if (frameRate.rate.isValid() || voteType == LayerVoteType::NoVote) { + if (frameRate.isValid()) { const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote; - info->setLayerVote({type, frameRate.rate, frameRate.seamlessness}); + info->setLayerVote({type, frameRate.vote.rate, frameRate.vote.seamlessness, + frameRate.category}); } else { info->resetLayerVote(); } diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index bae3739501..750803b2f9 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -26,10 +26,12 @@ #include #include +#include #include #include #include #include +#include #undef LOG_TAG #define LOG_TAG "LayerInfo" @@ -265,19 +267,34 @@ std::optional LayerInfo::calculateRefreshRateIfPossible(const RefreshRateSe : std::nullopt; } -LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateSelector& selector, - nsecs_t now) { +LayerInfo::RefreshRateVotes LayerInfo::getRefreshRateVote(const RefreshRateSelector& selector, + nsecs_t now) { ATRACE_CALL(); + LayerInfo::RefreshRateVotes votes; + if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) { - ALOGV("%s voted %d ", mName.c_str(), static_cast(mLayerVote.type)); - return mLayerVote; + if (mLayerVote.category != FrameRateCategory::Default) { + ALOGV("%s uses frame rate category: %d", mName.c_str(), + static_cast(mLayerVote.category)); + votes.push_back({LayerHistory::LayerVoteType::ExplicitCategory, mLayerVote.fps, + Seamlessness::Default, mLayerVote.category}); + } + + if (mLayerVote.fps.isValid() || + mLayerVote.type != LayerHistory::LayerVoteType::ExplicitDefault) { + ALOGV("%s voted %d ", mName.c_str(), static_cast(mLayerVote.type)); + votes.push_back(mLayerVote); + } + + return votes; } if (isAnimating(now)) { ATRACE_FORMAT_INSTANT("animating"); ALOGV("%s is animating", mName.c_str()); mLastRefreshRate.animating = true; - return {LayerHistory::LayerVoteType::Max, Fps()}; + votes.push_back({LayerHistory::LayerVoteType::Max, Fps()}); + return votes; } const LayerInfo::Frequent frequent = isFrequent(now); @@ -288,7 +305,8 @@ LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateSelector& se mLastRefreshRate.infrequent = true; // Infrequent layers vote for minimal refresh rate for // battery saving purposes and also to prevent b/135718869. - return {LayerHistory::LayerVoteType::Min, Fps()}; + votes.push_back({LayerHistory::LayerVoteType::Min, Fps()}); + return votes; } if (frequent.clearHistory) { @@ -298,11 +316,13 @@ LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateSelector& se auto refreshRate = calculateRefreshRateIfPossible(selector, now); if (refreshRate.has_value()) { ALOGV("%s calculated refresh rate: %s", mName.c_str(), to_string(*refreshRate).c_str()); - return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()}; + votes.push_back({LayerHistory::LayerVoteType::Heuristic, refreshRate.value()}); + return votes; } ALOGV("%s Max (can't resolve refresh rate)", mName.c_str()); - return {LayerHistory::LayerVoteType::Max, Fps()}; + votes.push_back({LayerHistory::LayerVoteType::Max, Fps()}); + return votes; } const char* LayerInfo::getTraceTag(LayerHistory::LayerVoteType type) const { @@ -391,6 +411,68 @@ bool LayerInfo::RefreshRateHistory::isConsistent() const { return consistent; } +LayerInfo::FrameRateCompatibility LayerInfo::FrameRate::convertCompatibility(int8_t compatibility) { + switch (compatibility) { + case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT: + return FrameRateCompatibility::Default; + case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE: + return FrameRateCompatibility::ExactOrMultiple; + case ANATIVEWINDOW_FRAME_RATE_EXACT: + return FrameRateCompatibility::Exact; + case ANATIVEWINDOW_FRAME_RATE_MIN: + return FrameRateCompatibility::Min; + case ANATIVEWINDOW_FRAME_RATE_NO_VOTE: + return FrameRateCompatibility::NoVote; + default: + LOG_ALWAYS_FATAL("Invalid frame rate compatibility value %d", compatibility); + return FrameRateCompatibility::Default; + } +} + +Seamlessness LayerInfo::FrameRate::convertChangeFrameRateStrategy(int8_t strategy) { + switch (strategy) { + case ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS: + return Seamlessness::OnlySeamless; + case ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS: + return Seamlessness::SeamedAndSeamless; + default: + LOG_ALWAYS_FATAL("Invalid change frame sate strategy value %d", strategy); + return Seamlessness::Default; + } +} + +FrameRateCategory LayerInfo::FrameRate::convertCategory(int8_t category) { + switch (category) { + case ANATIVEWINDOW_FRAME_RATE_CATEGORY_DEFAULT: + return FrameRateCategory::Default; + case ANATIVEWINDOW_FRAME_RATE_CATEGORY_NO_PREFERENCE: + return FrameRateCategory::NoPreference; + case ANATIVEWINDOW_FRAME_RATE_CATEGORY_LOW: + return FrameRateCategory::Low; + case ANATIVEWINDOW_FRAME_RATE_CATEGORY_NORMAL: + return FrameRateCategory::Normal; + case ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH: + return FrameRateCategory::High; + default: + LOG_ALWAYS_FATAL("Invalid frame rate category value %d", category); + return FrameRateCategory::Default; + } +} + +bool LayerInfo::FrameRate::isNoVote() const { + return vote.type == FrameRateCompatibility::NoVote || + category == FrameRateCategory::NoPreference; +} + +bool LayerInfo::FrameRate::isValid() const { + return isNoVote() || vote.rate.isValid() || category != FrameRateCategory::Default; +} + +std::ostream& operator<<(std::ostream& stream, const LayerInfo::FrameRate& rate) { + return stream << "{rate=" << rate.vote.rate << " type=" << ftl::enum_string(rate.vote.type) + << " seamlessness=" << ftl::enum_string(rate.vote.seamlessness) << '}'; +} + } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index c5a60573f5..7d2444c94b 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -25,6 +25,7 @@ #include #include +#include #include #include "LayerHistory.h" @@ -67,8 +68,15 @@ public: LayerHistory::LayerVoteType type = LayerHistory::LayerVoteType::Heuristic; Fps fps; Seamlessness seamlessness = Seamlessness::Default; + // Category is in effect if fps is not specified. + FrameRateCategory category = FrameRateCategory::Default; + + // Returns true if the layer explicitly should contribute to frame rate scoring. + bool isNoVote() const { return RefreshRateSelector::isNoVote(type, category); } }; + using RefreshRateVotes = ftl::SmallVector; + // FrameRateCompatibility specifies how we should interpret the frame rate associated with // the layer. enum class FrameRateCompatibility { @@ -87,24 +95,40 @@ public: ftl_last = NoVote }; - // Encapsulates the frame rate and compatibility of the layer. This information will be used + // Encapsulates the frame rate specifications of the layer. This information will be used // when the display refresh rate is determined. struct FrameRate { using Seamlessness = scheduler::Seamlessness; - Fps rate; - FrameRateCompatibility type = FrameRateCompatibility::Default; - Seamlessness seamlessness = Seamlessness::Default; + // Information related to a specific desired frame rate vote. + struct FrameRateVote { + Fps rate; + FrameRateCompatibility type = FrameRateCompatibility::Default; + Seamlessness seamlessness = Seamlessness::Default; + + bool operator==(const FrameRateVote& other) const { + return isApproxEqual(rate, other.rate) && type == other.type && + seamlessness == other.seamlessness; + } + + FrameRateVote() = default; + + FrameRateVote(Fps rate, FrameRateCompatibility type, + Seamlessness seamlessness = Seamlessness::OnlySeamless) + : rate(rate), type(type), seamlessness(getSeamlessness(rate, seamlessness)) {} + } vote; + + FrameRateCategory category = FrameRateCategory::Default; FrameRate() = default; FrameRate(Fps rate, FrameRateCompatibility type, - Seamlessness seamlessness = Seamlessness::OnlySeamless) - : rate(rate), type(type), seamlessness(getSeamlessness(rate, seamlessness)) {} + Seamlessness seamlessness = Seamlessness::OnlySeamless, + FrameRateCategory category = FrameRateCategory::Default) + : vote(FrameRateVote(rate, type, seamlessness)), category(category) {} bool operator==(const FrameRate& other) const { - return isApproxEqual(rate, other.rate) && type == other.type && - seamlessness == other.seamlessness; + return vote == other.vote && category == other.category; } bool operator!=(const FrameRate& other) const { return !(*this == other); } @@ -112,8 +136,22 @@ public: // Convert an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value to a // Layer::FrameRateCompatibility. Logs fatal if the compatibility value is invalid. static FrameRateCompatibility convertCompatibility(int8_t compatibility); + + // Convert an ANATIVEWINDOW_CHANGE_FRAME_RATE_* value to a scheduler::Seamlessness. + // Logs fatal if the compatibility value is invalid. static scheduler::Seamlessness convertChangeFrameRateStrategy(int8_t strategy); + // Convert an ANATIVEWINDOW_FRAME_RATE_CATEGORY_* value to a FrameRateCategory. + // Logs fatal if the compatibility value is invalid. + static FrameRateCategory convertCategory(int8_t category); + + // True if the FrameRate has explicit frame rate specifications. + bool isValid() const; + + // Returns true if the FrameRate explicitly instructs to not contribute to frame rate + // selection. + bool isNoVote() const; + private: static Seamlessness getSeamlessness(Fps rate, Seamlessness seamlessness) { if (!rate.isValid()) { @@ -148,13 +186,15 @@ public: void setDefaultLayerVote(LayerHistory::LayerVoteType type) { mDefaultVote = type; } // Resets the layer vote to its default. - void resetLayerVote() { mLayerVote = {mDefaultVote, Fps(), Seamlessness::Default}; } + void resetLayerVote() { + mLayerVote = {mDefaultVote, Fps(), Seamlessness::Default, FrameRateCategory::Default}; + } std::string getName() const { return mName; } uid_t getOwnerUid() const { return mOwnerUid; } - LayerVote getRefreshRateVote(const RefreshRateSelector&, nsecs_t now); + RefreshRateVotes getRefreshRateVote(const RefreshRateSelector&, nsecs_t now); // Return the last updated time. If the present time is farther in the future than the // updated time, the updated time is the present time. diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index fb985f7c5b..a7ba731323 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -275,6 +275,25 @@ std::pair RefreshRateSelector::getDisplayFrames(nsecs_t layerP return {quotient, remainder}; } +float RefreshRateSelector::calculateNonExactMatchingDefaultLayerScoreLocked( + nsecs_t displayPeriod, nsecs_t layerPeriod) const { + // Find the actual rate the layer will render, assuming + // that layerPeriod is the minimal period to render a frame. + // For example if layerPeriod is 20ms and displayPeriod is 16ms, + // then the actualLayerPeriod will be 32ms, because it is the + // smallest multiple of the display period which is >= layerPeriod. + auto actualLayerPeriod = displayPeriod; + int multiplier = 1; + while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) { + multiplier++; + actualLayerPeriod = displayPeriod * multiplier; + } + + // Because of the threshold we used above it's possible that score is slightly + // above 1. + return std::min(1.0f, static_cast(layerPeriod) / static_cast(actualLayerPeriod)); +} + float RefreshRateSelector::calculateNonExactMatchingLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate) const { constexpr float kScoreForFractionalPairs = .8f; @@ -282,22 +301,7 @@ float RefreshRateSelector::calculateNonExactMatchingLayerScoreLocked(const Layer const auto displayPeriod = refreshRate.getPeriodNsecs(); const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs(); if (layer.vote == LayerVoteType::ExplicitDefault) { - // Find the actual rate the layer will render, assuming - // that layerPeriod is the minimal period to render a frame. - // For example if layerPeriod is 20ms and displayPeriod is 16ms, - // then the actualLayerPeriod will be 32ms, because it is the - // smallest multiple of the display period which is >= layerPeriod. - auto actualLayerPeriod = displayPeriod; - int multiplier = 1; - while (layerPeriod > actualLayerPeriod + MARGIN_FOR_PERIOD_CALCULATION) { - multiplier++; - actualLayerPeriod = displayPeriod * multiplier; - } - - // Because of the threshold we used above it's possible that score is slightly - // above 1. - return std::min(1.0f, - static_cast(layerPeriod) / static_cast(actualLayerPeriod)); + return calculateNonExactMatchingDefaultLayerScoreLocked(displayPeriod, layerPeriod); } if (layer.vote == LayerVoteType::ExplicitExactOrMultiple || @@ -372,6 +376,22 @@ float RefreshRateSelector::calculateLayerScoreLocked(const LayerRequirement& lay constexpr float kSeamedSwitchPenalty = 0.95f; const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty; + if (layer.vote == LayerVoteType::ExplicitCategory) { + if (getFrameRateCategoryRange(layer.frameRateCategory).includes(refreshRate)) { + return 1.f; + } + + FpsRange categoryRange = getFrameRateCategoryRange(layer.frameRateCategory); + using fps_approx_ops::operator<; + if (refreshRate < categoryRange.min) { + return calculateNonExactMatchingDefaultLayerScoreLocked(refreshRate.getPeriodNsecs(), + categoryRange.min + .getPeriodNsecs()); + } + return calculateNonExactMatchingDefaultLayerScoreLocked(refreshRate.getPeriodNsecs(), + categoryRange.max.getPeriodNsecs()); + } + // If the layer wants Max, give higher score to the higher refresh rate if (layer.vote == LayerVoteType::Max) { return calculateDistanceScoreFromMax(refreshRate); @@ -391,7 +411,8 @@ float RefreshRateSelector::calculateLayerScoreLocked(const LayerRequirement& lay // If the layer frame rate is a divisor of the refresh rate it should score // the highest score. - if (getFrameRateDivisor(refreshRate, layer.desiredRefreshRate) > 0) { + if (layer.desiredRefreshRate.isValid() && + getFrameRateDivisor(refreshRate, layer.desiredRefreshRate) > 0) { return 1.0f * seamlessness; } @@ -441,6 +462,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector 0 || - explicitExactOrMultipleVoteLayers > 0 || explicitExact > 0; + explicitExactOrMultipleVoteLayers > 0 || explicitExact > 0 || + explicitCategoryVoteLayers > 0; const Policy* policy = getCurrentPolicyLocked(); const auto& defaultMode = mDisplayModes.get(policy->defaultMode)->get(); @@ -536,10 +562,11 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vectorvote != LayerVoteType::ExplicitDefault && - layer->vote != LayerVoteType::ExplicitExactOrMultiple && - layer->vote != LayerVoteType::ExplicitExact); + layer->vote != LayerVoteType::ExplicitExactOrMultiple && + layer->vote != LayerVoteType::ExplicitExact && + layer->vote != LayerVoteType::ExplicitCategory, + "Invalid layer vote type for frame rate overrides"); for (auto& [fps, score] : scoredFrameRates) { constexpr bool isSeamlessSwitch = true; const auto layerScore = calculateLayerScoreLocked(*layer, fps, isSeamlessSwitch); @@ -1380,6 +1411,27 @@ std::chrono::milliseconds RefreshRateSelector::getIdleTimerTimeout() { return mConfig.idleTimerTimeout; } +// TODO(b/293651105): Extract category FpsRange mapping to OEM-configurable config. +FpsRange RefreshRateSelector::getFrameRateCategoryRange(FrameRateCategory category) { + switch (category) { + case FrameRateCategory::High: + return FpsRange{90_Hz, 120_Hz}; + case FrameRateCategory::Normal: + return FpsRange{60_Hz, 90_Hz}; + case FrameRateCategory::Low: + return FpsRange{30_Hz, 60_Hz}; + case FrameRateCategory::NoPreference: + case FrameRateCategory::Default: + LOG_ALWAYS_FATAL("Should not get fps range for frame rate category: %s", + ftl::enum_string(category).c_str()); + return FpsRange{0_Hz, 0_Hz}; + default: + LOG_ALWAYS_FATAL("Invalid frame rate category for range: %s", + ftl::enum_string(category).c_str()); + return FpsRange{0_Hz, 0_Hz}; + } +} + } // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h index 7af8d0397f..41db38d705 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h @@ -147,8 +147,9 @@ public: // ExactOrMultiple compatibility ExplicitExact, // Specific refresh rate that was provided by the app with // Exact compatibility + ExplicitCategory, // Specific frame rate category was provided by the app - ftl_last = ExplicitExact + ftl_last = ExplicitCategory }; // Captures the layer requirements for a refresh rate. This will be used to determine the @@ -164,6 +165,8 @@ public: Fps desiredRefreshRate; // If a seamless mode switch is required. Seamlessness seamlessness = Seamlessness::Default; + // Layer frame rate category. Superseded by desiredRefreshRate. + FrameRateCategory frameRateCategory = FrameRateCategory::Default; // Layer's weight in the range of [0, 1]. The higher the weight the more impact this layer // would have on choosing the refresh rate. float weight = 0.0f; @@ -174,12 +177,20 @@ public: return name == other.name && vote == other.vote && isApproxEqual(desiredRefreshRate, other.desiredRefreshRate) && seamlessness == other.seamlessness && weight == other.weight && - focused == other.focused; + focused == other.focused && frameRateCategory == other.frameRateCategory; } bool operator!=(const LayerRequirement& other) const { return !(*this == other); } + + bool isNoVote() const { return RefreshRateSelector::isNoVote(vote, frameRateCategory); } }; + // Returns true if the layer explicitly instructs to not contribute to refresh rate selection. + // In other words, true if the layer should be ignored. + static bool isNoVote(LayerVoteType vote, FrameRateCategory category) { + return vote == LayerVoteType::NoVote || category == FrameRateCategory::NoPreference; + } + // Global state describing signals that affect refresh rate choice. struct GlobalSignals { // Whether the user touched the screen recently. Used to apply touch boost. @@ -344,6 +355,9 @@ public: Fps displayFrameRate, GlobalSignals) const EXCLUDES(mLock); + // Gets the FpsRange that the FrameRateCategory represents. + static FpsRange getFrameRateCategoryRange(FrameRateCategory category); + std::optional kernelIdleTimerController() { return mConfig.kernelIdleTimerController; } @@ -447,6 +461,11 @@ private: float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&, Fps refreshRate) const REQUIRES(mLock); + // Calculates the score for non-exact matching layer that has LayerVoteType::ExplicitDefault. + float calculateNonExactMatchingDefaultLayerScoreLocked(nsecs_t displayPeriod, + nsecs_t layerPeriod) const + REQUIRES(mLock); + void updateDisplayModes(DisplayModes, DisplayModeId activeModeId) EXCLUDES(mLock) REQUIRES(kMainThreadContext); diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h index d6329e246c..19e951abb2 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/Fps.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/Fps.h @@ -23,6 +23,7 @@ #include #include +#include #include namespace android { @@ -81,6 +82,17 @@ struct FpsRanges { bool valid() const; }; +// The frame rate category of a Layer. +enum class FrameRateCategory { + Default, + NoPreference, + Low, + Normal, + High, + + ftl_last = High +}; + static_assert(std::is_trivially_copyable_v); constexpr Fps operator""_Hz(unsigned long long frequency) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 06adfec0d2..5c25dbce0c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5192,9 +5192,15 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime const auto strategy = Layer::FrameRate::convertChangeFrameRateStrategy(s.changeFrameRateStrategy); - if (layer->setFrameRate( - Layer::FrameRate(Fps::fromValue(s.frameRate), compatibility, strategy))) { - flags |= eTraversalNeeded; + if (layer->setFrameRate(Layer::FrameRate::FrameRateVote(Fps::fromValue(s.frameRate), + compatibility, strategy))) { + flags |= eTraversalNeeded; + } + } + if (what & layer_state_t::eFrameRateCategoryChanged) { + const FrameRateCategory category = Layer::FrameRate::convertCategory(s.frameRateCategory); + if (layer->setFrameRateCategory(category)) { + flags |= eTraversalNeeded; } } if (what & layer_state_t::eFixedTransformHintChanged) { diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h index f64ba2a439..93438d8666 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h @@ -335,6 +335,17 @@ protected: mLifecycleManager.applyTransactions(transactions); } + void setFrameRateCategory(uint32_t id, int8_t frameRateCategory) { + std::vector transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + + transactions.back().states.front().state.what = layer_state_t::eFrameRateCategoryChanged; + transactions.back().states.front().layerId = id; + transactions.back().states.front().state.frameRateCategory = frameRateCategory; + mLifecycleManager.applyTransactions(transactions); + } + void setRoundedCorners(uint32_t id, float radius) { std::vector transactions; transactions.emplace_back(); diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 85d86a7acc..51b5b05bed 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -437,6 +437,117 @@ TEST_F(LayerHistoryTest, oneLayerExplicitExactVote) { EXPECT_EQ(0, frequentLayerCount(time)); } +TEST_F(LayerHistoryTest, oneLayerExplicitCategory) { + auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()) + .WillRepeatedly( + Return(Layer::FrameRate(0_Hz, Layer::FrameRateCompatibility::Default, + Seamlessness::OnlySeamless, FrameRateCategory::High))); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + history().record(layer->getSequence(), layer->getLayerProps(), time, time, + LayerHistory::LayerUpdateType::Buffer); + time += HI_FPS_PERIOD; + } + + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + // First LayerRequirement is the frame rate specification + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory); + + // layer became inactive, but the vote stays + setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); + time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory); +} + +// This test case should be the same as oneLayerNoVote except instead of layer vote is NoVote, +// the category is NoPreference. +TEST_F(LayerHistoryTest, oneLayerCategoryNoPreference) { + auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()) + .WillRepeatedly(Return(Layer::FrameRate(0_Hz, Layer::FrameRateCompatibility::Default, + Seamlessness::OnlySeamless, + FrameRateCategory::NoPreference))); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + history().record(layer->getSequence(), layer->getLayerProps(), time, time, + LayerHistory::LayerUpdateType::Buffer); + time += HI_FPS_PERIOD; + } + + ASSERT_TRUE(summarizeLayerHistory(time).empty()); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + + // layer became inactive + time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); + ASSERT_TRUE(summarizeLayerHistory(time).empty()); + EXPECT_EQ(0, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); +} + +TEST_F(LayerHistoryTest, oneLayerExplicitVoteWithCategory) { + auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()) + .WillRepeatedly( + Return(Layer::FrameRate(73.4_Hz, Layer::FrameRateCompatibility::Default, + Seamlessness::OnlySeamless, FrameRateCategory::High))); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + history().record(layer->getSequence(), layer->getLayerProps(), time, time, + LayerHistory::LayerUpdateType::Buffer); + time += HI_FPS_PERIOD; + } + + // There are 2 LayerRequirement's due to the frame rate category. + ASSERT_EQ(2, summarizeLayerHistory(time).size()); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + // First LayerRequirement is the layer's category specification + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory); + + // Second LayerRequirement is the frame rate specification + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[1].vote); + EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[1].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[1].frameRateCategory); + + // layer became inactive, but the vote stays + setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); + time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); + ASSERT_EQ(2, summarizeLayerHistory(time).size()); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory); +} + TEST_F(LayerHistoryTest, multipleLayers) { auto layer1 = createLayer("A"); auto layer2 = createLayer("B"); diff --git a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp index 5c2d2e1f43..e0133d6010 100644 --- a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp @@ -24,13 +24,23 @@ #include "FpsOps.h" #include "Scheduler/LayerHistory.h" #include "Scheduler/LayerInfo.h" +#include "TestableScheduler.h" +#include "TestableSurfaceFlinger.h" +#include "mock/MockSchedulerCallback.h" namespace android::scheduler { +using android::mock::createDisplayMode; + class LayerInfoTest : public testing::Test { protected: using FrameTimeData = LayerInfo::FrameTimeData; + static constexpr Fps LO_FPS = 30_Hz; + static constexpr Fps HI_FPS = 90_Hz; + + LayerInfoTest() { mFlinger.resetScheduler(mScheduler); } + void setFrameTimes(const std::deque& frameTimes) { layerInfo.mFrameTimes = frameTimes; } @@ -43,6 +53,16 @@ protected: auto calculateAverageFrameTime() { return layerInfo.calculateAverageFrameTime(); } LayerInfo layerInfo{"TestLayerInfo", 0, LayerHistory::LayerVoteType::Heuristic}; + + std::shared_ptr mSelector = + std::make_shared(makeModes(createDisplayMode(DisplayModeId(0), + LO_FPS), + createDisplayMode(DisplayModeId(1), + HI_FPS)), + DisplayModeId(0)); + mock::SchedulerCallback mSchedulerCallback; + TestableScheduler* mScheduler = new TestableScheduler(mSelector, mSchedulerCallback); + TestableSurfaceFlinger mFlinger; }; namespace { @@ -171,5 +191,63 @@ TEST_F(LayerInfoTest, ignoresLargePeriods) { ASSERT_EQ(kExpectedFps, Fps::fromPeriodNsecs(*averageFrameTime)); } +TEST_F(LayerInfoTest, getRefreshRateVote_explicitVote) { + LayerInfo::LayerVote vote = {.type = LayerHistory::LayerVoteType::ExplicitDefault, + .fps = 20_Hz}; + layerInfo.setLayerVote(vote); + + auto actualVotes = + layerInfo.getRefreshRateVote(*mScheduler->refreshRateSelector(), systemTime()); + ASSERT_EQ(actualVotes.size(), 1u); + ASSERT_EQ(actualVotes[0].type, vote.type); + ASSERT_EQ(actualVotes[0].fps, vote.fps); + ASSERT_EQ(actualVotes[0].seamlessness, vote.seamlessness); + ASSERT_EQ(actualVotes[0].category, vote.category); +} + +TEST_F(LayerInfoTest, getRefreshRateVote_explicitVoteWithCategory) { + LayerInfo::LayerVote vote = {.type = LayerHistory::LayerVoteType::ExplicitDefault, + .fps = 20_Hz, + .category = FrameRateCategory::High}; + layerInfo.setLayerVote(vote); + + auto actualVotes = + layerInfo.getRefreshRateVote(*mScheduler->refreshRateSelector(), systemTime()); + ASSERT_EQ(actualVotes.size(), 2u); + ASSERT_EQ(actualVotes[0].type, LayerHistory::LayerVoteType::ExplicitCategory); + ASSERT_EQ(actualVotes[0].category, vote.category); + ASSERT_EQ(actualVotes[1].type, vote.type); + ASSERT_EQ(actualVotes[1].fps, vote.fps); + ASSERT_EQ(actualVotes[1].seamlessness, vote.seamlessness); + ASSERT_EQ(actualVotes[1].category, vote.category); +} + +TEST_F(LayerInfoTest, getRefreshRateVote_explicitCategory) { + // When a layer only has a category set, the LayerVoteType should be the LayerInfo's default. + // The most common case should be Heuristic. + LayerInfo::LayerVote vote = {.type = LayerHistory::LayerVoteType::ExplicitDefault, + .category = FrameRateCategory::High}; + layerInfo.setLayerVote(vote); + + auto actualVotes = + layerInfo.getRefreshRateVote(*mScheduler->refreshRateSelector(), systemTime()); + ASSERT_EQ(actualVotes.size(), 1u); + ASSERT_EQ(actualVotes[0].type, LayerHistory::LayerVoteType::ExplicitCategory); + ASSERT_EQ(actualVotes[0].category, vote.category); +} + +TEST_F(LayerInfoTest, getRefreshRateVote_noData) { + LayerInfo::LayerVote vote = { + .type = LayerHistory::LayerVoteType::Heuristic, + }; + layerInfo.setLayerVote(vote); + + auto actualVotes = + layerInfo.getRefreshRateVote(*mScheduler->refreshRateSelector(), systemTime()); + ASSERT_EQ(actualVotes.size(), 1u); + ASSERT_EQ(actualVotes[0].type, LayerHistory::LayerVoteType::Max); + ASSERT_EQ(actualVotes[0].fps, vote.fps); +} + } // namespace } // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 84c37759ba..67cd4c67eb 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -314,13 +314,15 @@ TEST_F(LayerSnapshotTest, NoLayerVoteForParentWithChildVotes) { mLifecycleManager.applyTransactions(transactions); UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); - EXPECT_EQ(getSnapshot(11)->frameRate.rate.getIntValue(), 90); - EXPECT_EQ(getSnapshot(11)->frameRate.type, scheduler::LayerInfo::FrameRateCompatibility::Exact); - EXPECT_EQ(getSnapshot(111)->frameRate.rate.getIntValue(), 90); - EXPECT_EQ(getSnapshot(111)->frameRate.type, + EXPECT_EQ(getSnapshot(11)->frameRate.vote.rate.getIntValue(), 90); + EXPECT_EQ(getSnapshot(11)->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Exact); - EXPECT_EQ(getSnapshot(1)->frameRate.rate.getIntValue(), 0); - EXPECT_EQ(getSnapshot(1)->frameRate.type, scheduler::LayerInfo::FrameRateCompatibility::NoVote); + EXPECT_EQ(getSnapshot(111)->frameRate.vote.rate.getIntValue(), 90); + EXPECT_EQ(getSnapshot(111)->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Exact); + EXPECT_EQ(getSnapshot(1)->frameRate.vote.rate.getIntValue(), 0); + EXPECT_EQ(getSnapshot(1)->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::NoVote); } TEST_F(LayerSnapshotTest, CanCropTouchableRegion) { @@ -525,21 +527,21 @@ TEST_F(LayerSnapshotTest, framerate) { UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); // verify parent is gets no vote - EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 1})->frameRate.type, + EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::NoVote); EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate)); // verify layer and children get the requested votes - EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 11})->frameRate.rate.getValue(), 244.f); - EXPECT_EQ(getSnapshot({.id = 11})->frameRate.type, + EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 11})->changes.test(RequestedLayerState::Changes::FrameRate)); - EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 111})->frameRate.rate.getValue(), 244.f); - EXPECT_EQ(getSnapshot({.id = 111})->frameRate.type, + EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 111})->changes.test(RequestedLayerState::Changes::FrameRate)); @@ -549,24 +551,24 @@ TEST_F(LayerSnapshotTest, framerate) { std::vector expected = {1, 11, 111, 122, 1221, 12, 121, 13, 2}; UPDATE_AND_VERIFY(mSnapshotBuilder, expected); // verify parent is gets no vote - EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 1})->frameRate.type, + EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::NoVote); // verify layer and children get the requested votes - EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 11})->frameRate.rate.getValue(), 244.f); - EXPECT_EQ(getSnapshot({.id = 11})->frameRate.type, + EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); - EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 111})->frameRate.rate.getValue(), 244.f); - EXPECT_EQ(getSnapshot({.id = 111})->frameRate.type, + EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); - EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 122})->frameRate.rate.getValue(), 244.f); - EXPECT_EQ(getSnapshot({.id = 122})->frameRate.type, + EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 122})->changes.test(RequestedLayerState::Changes::FrameRate)); @@ -576,31 +578,31 @@ TEST_F(LayerSnapshotTest, framerate) { UPDATE_AND_VERIFY(mSnapshotBuilder, expected); // verify old parent has invalid framerate (default) - EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 1})->frameRate.type, + EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate)); // verify new parent get no vote - EXPECT_FALSE(getSnapshot({.id = 2})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 2})->frameRate.type, + EXPECT_FALSE(getSnapshot({.id = 2})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 2})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::NoVote); EXPECT_TRUE(getSnapshot({.id = 2})->changes.test(RequestedLayerState::Changes::FrameRate)); // verify layer and children get the requested votes (unchanged) - EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 11})->frameRate.rate.getValue(), 244.f); - EXPECT_EQ(getSnapshot({.id = 11})->frameRate.type, + EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); - EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 111})->frameRate.rate.getValue(), 244.f); - EXPECT_EQ(getSnapshot({.id = 111})->frameRate.type, + EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); - EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.rate.isValid()); - EXPECT_EQ(getSnapshot({.id = 122})->frameRate.rate.getValue(), 244.f); - EXPECT_EQ(getSnapshot({.id = 122})->frameRate.type, + EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.type, scheduler::LayerInfo::FrameRateCompatibility::Default); } @@ -610,6 +612,112 @@ TEST_F(LayerSnapshotTest, translateDataspace) { EXPECT_EQ(getSnapshot({.id = 1})->dataspace, ui::Dataspace::V0_SRGB); } +// This test is similar to "frameRate" test case but checks that the setFrameRateCategory API +// interaction also works correctly with the setFrameRate API within SF frontend. +TEST_F(LayerSnapshotTest, frameRateWithCategory) { + // ROOT + // ├── 1 + // │ ├── 11 (frame rate set to 244.f) + // │ │ └── 111 + // │ ├── 12 + // │ │ ├── 121 + // │ │ └── 122 (frame rate category set to Normal) + // │ │ └── 1221 + // │ └── 13 + // └── 2 + setFrameRate(11, 244.f, 0, 0); + setFrameRateCategory(122, 3 /* Normal */); + + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + // verify parent 1 gets no vote + EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::NoVote); + EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate)); + + // verify layer 11 and children 111 get the requested votes + EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + EXPECT_TRUE(getSnapshot({.id = 11})->changes.test(RequestedLayerState::Changes::FrameRate)); + + EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + EXPECT_TRUE(getSnapshot({.id = 111})->changes.test(RequestedLayerState::Changes::FrameRate)); + + // verify parent 12 gets no vote + EXPECT_FALSE(getSnapshot({.id = 12})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 12})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::NoVote); + EXPECT_TRUE(getSnapshot({.id = 12})->changes.test(RequestedLayerState::Changes::FrameRate)); + + // verify layer 122 and children 1221 get the requested votes + EXPECT_FALSE(getSnapshot({.id = 122})->frameRate.vote.rate.isValid()); + EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.isValid()); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.category, FrameRateCategory::Normal); + EXPECT_TRUE(getSnapshot({.id = 122})->changes.test(RequestedLayerState::Changes::FrameRate)); + + EXPECT_FALSE(getSnapshot({.id = 1221})->frameRate.vote.rate.isValid()); + EXPECT_TRUE(getSnapshot({.id = 1221})->frameRate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.category, FrameRateCategory::Normal); + EXPECT_TRUE(getSnapshot({.id = 1221})->changes.test(RequestedLayerState::Changes::FrameRate)); + + // reparent and verify the child does NOT get the new parent's framerate because it already has + // the frame rate category specified. + // ROOT + // ├─1 + // │ ├─11 (frame rate set to 244.f) + // │ │ ├─111 + // │ │ └─122 (frame rate category set to Normal) + // │ │ └─1221 + // │ ├─12 + // │ │ └─121 + // │ └─13 + // └─2 + reparentLayer(122, 11); + + std::vector expected = {1, 11, 111, 122, 1221, 12, 121, 13, 2}; + UPDATE_AND_VERIFY(mSnapshotBuilder, expected); + // verify parent is gets no vote + EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::NoVote); + + // verify layer 11 and children 111 get the requested votes + EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + + EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + + // verify layer 122 and children 1221 get the requested category vote (unchanged from + // reparenting) + EXPECT_FALSE(getSnapshot({.id = 122})->frameRate.vote.rate.isValid()); + EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.isValid()); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.category, FrameRateCategory::Normal); + EXPECT_TRUE(getSnapshot({.id = 122})->changes.test(RequestedLayerState::Changes::FrameRate)); + + EXPECT_FALSE(getSnapshot({.id = 1221})->frameRate.vote.rate.isValid()); + EXPECT_TRUE(getSnapshot({.id = 1221})->frameRate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.category, FrameRateCategory::Normal); + EXPECT_TRUE(getSnapshot({.id = 1221})->changes.test(RequestedLayerState::Changes::FrameRate)); +} + TEST_F(LayerSnapshotTest, skipRoundCornersWhenProtected) { setRoundedCorners(1, 42.f); setRoundedCorners(2, 42.f); diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index aaf55fbeae..dc6b70032a 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include "DisplayHardware/HWC2.h" #include "FpsOps.h" @@ -1381,6 +1382,120 @@ TEST_P(RefreshRateSelectorTest, touchConsidered) { EXPECT_FALSE(signals.touch); } +TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_30_60_90_120) { + auto selector = createSelector(makeModes(kMode30, kMode60, kMode90, kMode120), kModeId60); + + std::vector layers = {{.vote = LayerVoteType::ExplicitDefault, .weight = 1.f}, + {.vote = LayerVoteType::ExplicitCategory, + .weight = 1.f}}; + auto& lr = layers[0]; + + struct Case { + // Params + Fps desiredFrameRate = 0_Hz; + FrameRateCategory frameRateCategory = FrameRateCategory::Default; + + // Expected result + Fps expectedFrameRate = 0_Hz; + }; + + // Prepare a table with the vote and the expected refresh rate + const std::initializer_list testCases = { + // Cases that only have frame rate category requirements, but no desired frame rate. + // When frame rates get an equal score, the lower is chosen, unless there are Max votes. + {0_Hz, FrameRateCategory::High, 90_Hz}, + {0_Hz, FrameRateCategory::Normal, 60_Hz}, + {0_Hz, FrameRateCategory::Low, 30_Hz}, + {0_Hz, FrameRateCategory::NoPreference, 60_Hz}, + + // Cases that have both desired frame rate and frame rate category requirements. + {24_Hz, FrameRateCategory::High, 120_Hz}, + {30_Hz, FrameRateCategory::High, 90_Hz}, + {12_Hz, FrameRateCategory::Normal, 60_Hz}, + {30_Hz, FrameRateCategory::NoPreference, 30_Hz}, + + // Cases that only have desired frame rate. + {30_Hz, FrameRateCategory::Default, 30_Hz}, + }; + + for (auto testCase : testCases) { + ALOGI("**** %s: Testing desiredFrameRate=%s, frameRateCategory=%s", __func__, + to_string(testCase.desiredFrameRate).c_str(), + ftl::enum_string(testCase.frameRateCategory).c_str()); + + lr.desiredRefreshRate = testCase.desiredFrameRate; + + std::stringstream ss; + ss << to_string(testCase.desiredFrameRate) + << ", category=" << ftl::enum_string(testCase.frameRateCategory); + lr.name = ss.str(); + + if (testCase.frameRateCategory != FrameRateCategory::Default) { + layers[1].frameRateCategory = testCase.frameRateCategory; + } + + EXPECT_EQ(testCase.expectedFrameRate, selector.getBestFrameRateMode(layers)->getFps()) + << "did not get expected frame rate for " << lr.name; + } +} + +TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_60_120) { + auto selector = createSelector(makeModes(kMode60, kMode120), kModeId60); + + std::vector layers = {{.vote = LayerVoteType::ExplicitDefault, .weight = 1.f}, + {.vote = LayerVoteType::ExplicitCategory, + .weight = 1.f}}; + auto& lr = layers[0]; + + struct Case { + // Params + Fps desiredFrameRate = 0_Hz; + FrameRateCategory frameRateCategory = FrameRateCategory::Default; + + // Expected result + Fps expectedFrameRate = 0_Hz; + }; + + // Prepare a table with the vote and the expected refresh rate + const std::initializer_list testCases = { + // Cases that only have frame rate category requirements, but no desired frame rate. + // When frame rates get an equal score, the lower is chosen, unless there are Max votes. + {0_Hz, FrameRateCategory::High, 120_Hz}, + {0_Hz, FrameRateCategory::Normal, 60_Hz}, + {0_Hz, FrameRateCategory::Low, 60_Hz}, + {0_Hz, FrameRateCategory::NoPreference, 60_Hz}, + + // Cases that have both desired frame rate and frame rate category requirements. + {24_Hz, FrameRateCategory::High, 120_Hz}, + {30_Hz, FrameRateCategory::High, 120_Hz}, + {12_Hz, FrameRateCategory::Normal, 60_Hz}, + {30_Hz, FrameRateCategory::NoPreference, 60_Hz}, + + // Cases that only have desired frame rate. + {30_Hz, FrameRateCategory::Default, 60_Hz}, + }; + + for (auto testCase : testCases) { + ALOGI("**** %s: Testing desiredFrameRate=%s, frameRateCategory=%s", __func__, + to_string(testCase.desiredFrameRate).c_str(), + ftl::enum_string(testCase.frameRateCategory).c_str()); + + lr.desiredRefreshRate = testCase.desiredFrameRate; + + std::stringstream ss; + ss << to_string(testCase.desiredFrameRate) + << ", category=" << ftl::enum_string(testCase.frameRateCategory); + lr.name = ss.str(); + + if (testCase.frameRateCategory != FrameRateCategory::Default) { + layers[1].frameRateCategory = testCase.frameRateCategory; + } + + EXPECT_EQ(testCase.expectedFrameRate, selector.getBestFrameRateMode(layers)->getFps()) + << "did not get expected frame rate for " << lr.name; + } +} + TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_ExplicitDefault) { auto selector = createSelector(kModes_60_90_72_120, kModeId60); diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index a1e4e25c06..608fa762ef 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -97,7 +97,7 @@ TEST_P(SetFrameRateTest, SetAndGet) { const auto& layerFactory = GetParam(); auto layer = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); - layer->setFrameRate(FRAME_RATE_VOTE1); + layer->setFrameRate(FRAME_RATE_VOTE1.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE1, layer->getFrameRateForLayerTree()); } @@ -114,13 +114,13 @@ TEST_P(SetFrameRateTest, SetAndGetParent) { addChild(parent, child1); addChild(child1, child2); - child2->setFrameRate(FRAME_RATE_VOTE1); + child2->setFrameRate(FRAME_RATE_VOTE1.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); - child2->setFrameRate(FRAME_RATE_NO_VOTE); + child2->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); @@ -139,27 +139,27 @@ TEST_P(SetFrameRateTest, SetAndGetParentAllVote) { addChild(parent, child1); addChild(child1, child2); - child2->setFrameRate(FRAME_RATE_VOTE1); - child1->setFrameRate(FRAME_RATE_VOTE2); - parent->setFrameRate(FRAME_RATE_VOTE3); + child2->setFrameRate(FRAME_RATE_VOTE1.vote); + child1->setFrameRate(FRAME_RATE_VOTE2.vote); + parent->setFrameRate(FRAME_RATE_VOTE3.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); - child2->setFrameRate(FRAME_RATE_NO_VOTE); + child2->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE2, child2->getFrameRateForLayerTree()); - child1->setFrameRate(FRAME_RATE_NO_VOTE); + child1->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE3, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE3, child2->getFrameRateForLayerTree()); - parent->setFrameRate(FRAME_RATE_NO_VOTE); + parent->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); @@ -178,13 +178,13 @@ TEST_P(SetFrameRateTest, SetAndGetChild) { addChild(parent, child1); addChild(child1, child2); - parent->setFrameRate(FRAME_RATE_VOTE1); + parent->setFrameRate(FRAME_RATE_VOTE1.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); - parent->setFrameRate(FRAME_RATE_NO_VOTE); + parent->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); @@ -203,27 +203,27 @@ TEST_P(SetFrameRateTest, SetAndGetChildAllVote) { addChild(parent, child1); addChild(child1, child2); - child2->setFrameRate(FRAME_RATE_VOTE1); - child1->setFrameRate(FRAME_RATE_VOTE2); - parent->setFrameRate(FRAME_RATE_VOTE3); + child2->setFrameRate(FRAME_RATE_VOTE1.vote); + child1->setFrameRate(FRAME_RATE_VOTE2.vote); + parent->setFrameRate(FRAME_RATE_VOTE3.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); - parent->setFrameRate(FRAME_RATE_NO_VOTE); + parent->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); - child1->setFrameRate(FRAME_RATE_NO_VOTE); + child1->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); - child2->setFrameRate(FRAME_RATE_NO_VOTE); + child2->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); @@ -241,7 +241,7 @@ TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) { addChild(parent, child1); - parent->setFrameRate(FRAME_RATE_VOTE1); + parent->setFrameRate(FRAME_RATE_VOTE1.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree()); @@ -253,7 +253,7 @@ TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) { EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); - parent->setFrameRate(FRAME_RATE_NO_VOTE); + parent->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); @@ -272,7 +272,7 @@ TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) { addChild(parent, child1); addChild(child1, child2); - parent->setFrameRate(FRAME_RATE_VOTE1); + parent->setFrameRate(FRAME_RATE_VOTE1.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree()); @@ -284,7 +284,7 @@ TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) { EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); - parent->setFrameRate(FRAME_RATE_NO_VOTE); + parent->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); @@ -305,14 +305,14 @@ TEST_P(SetFrameRateTest, SetAndGetParentNotInTree) { addChild(child1, child2); addChild(child1, child2_1); - child2->setFrameRate(FRAME_RATE_VOTE1); + child2->setFrameRate(FRAME_RATE_VOTE1.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child2_1->getFrameRateForLayerTree()); - child2->setFrameRate(FRAME_RATE_NO_VOTE); + child2->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); @@ -375,7 +375,7 @@ TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { auto child = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); addChild(parent, child); - parent->setFrameRate(FRAME_RATE_VOTE1); + parent->setFrameRate(FRAME_RATE_VOTE1.vote); commitTransaction(); auto& history = mFlinger.mutableScheduler().mutableLayerHistory(); @@ -388,8 +388,8 @@ TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { const auto summary = history.summarize(*selectorPtr, 0); ASSERT_EQ(2u, summary.size()); - EXPECT_EQ(FRAME_RATE_VOTE1.rate, summary[0].desiredRefreshRate); - EXPECT_EQ(FRAME_RATE_VOTE1.rate, summary[1].desiredRefreshRate); + EXPECT_EQ(FRAME_RATE_VOTE1.vote.rate, summary[0].desiredRefreshRate); + EXPECT_EQ(FRAME_RATE_VOTE1.vote.rate, summary[1].desiredRefreshRate); } TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) { @@ -405,7 +405,7 @@ TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) { addChild(parent, child1); addChild(child1, childOfChild1); - childOfChild1->setFrameRate(FRAME_RATE_VOTE1); + childOfChild1->setFrameRate(FRAME_RATE_VOTE1.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); @@ -419,7 +419,7 @@ TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) { EXPECT_EQ(FRAME_RATE_VOTE1, childOfChild1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); - childOfChild1->setFrameRate(FRAME_RATE_NO_VOTE); + childOfChild1->setFrameRate(FRAME_RATE_NO_VOTE.vote); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); -- cgit v1.2.3-59-g8ed1b From 9ac5e6e6b2a9700268165c6556d30afe24fc204c Mon Sep 17 00:00:00 2001 From: Tony Huang Date: Thu, 24 Aug 2023 09:01:44 +0000 Subject: VRR: Allowlist for small area detection Add a allowlist mechanism for suppress frame rate when small area. In this patch, we will keep a array list to record pkg name which want to apply the small area detection for suppressing frame rate and its threshold value of small area ratio. In framewokr, we will check the all pkg uid by pkg name from package manager and call a native function which include uid and threshold. In SF native, it get the threshold of uid and we will save them as a map, and it will used to check should it apply small area detection and what threshold it should use. Bug: 281720315 Test: atest SmallAreaDetectionMappingsTest Test: atest LayerHistoryTest Change-Id: Iaf6c0090f9db499fc5ed097b2d3c6d9d871d4812 --- libs/gui/SurfaceComposerClient.cpp | 14 +++++ libs/gui/aidl/android/gui/ISurfaceComposer.aidl | 9 ++++ libs/gui/fuzzer/libgui_fuzzer_utils.h | 3 ++ libs/gui/include/gui/SurfaceComposerClient.h | 10 ++++ libs/gui/tests/Surface_test.cpp | 9 ++++ services/surfaceflinger/Android.bp | 1 + services/surfaceflinger/Layer.cpp | 3 +- services/surfaceflinger/Scheduler/LayerHistory.cpp | 4 +- services/surfaceflinger/Scheduler/LayerHistory.h | 4 +- services/surfaceflinger/Scheduler/Scheduler.cpp | 16 ++++++ services/surfaceflinger/Scheduler/Scheduler.h | 14 +++-- .../Scheduler/SmallAreaDetectionAllowMappings.cpp | 47 +++++++++++++++++ .../Scheduler/SmallAreaDetectionAllowMappings.h | 39 ++++++++++++++ services/surfaceflinger/SurfaceFlinger.cpp | 45 ++++++++++++++++ services/surfaceflinger/SurfaceFlinger.h | 7 +++ services/surfaceflinger/tests/unittests/Android.bp | 1 + .../SmallAreaDetectionAllowMappingsTest.cpp | 61 ++++++++++++++++++++++ 17 files changed, 276 insertions(+), 11 deletions(-) create mode 100644 services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp create mode 100644 services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h create mode 100644 services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 92589c5742..4719e246e7 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2768,6 +2768,20 @@ status_t SurfaceComposerClient::setOverrideFrameRate(uid_t uid, float frameRate) return statusTFromBinderStatus(status); } +status_t SurfaceComposerClient::updateSmallAreaDetection(std::vector& uids, + std::vector& thresholds) { + binder::Status status = + ComposerServiceAIDL::getComposerService()->updateSmallAreaDetection(uids, thresholds); + return statusTFromBinderStatus(status); +} + +status_t SurfaceComposerClient::setSmallAreaDetectionThreshold(uid_t uid, float threshold) { + binder::Status status = + ComposerServiceAIDL::getComposerService()->setSmallAreaDetectionThreshold(uid, + threshold); + return statusTFromBinderStatus(status); +} + void SurfaceComposerClient::setAutoLowLatencyMode(const sp& display, bool on) { ComposerServiceAIDL::getComposerService()->setAutoLowLatencyMode(display, on); } diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index c2f47fc5ba..1c604a1f8b 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -479,6 +479,15 @@ interface ISurfaceComposer { */ void setOverrideFrameRate(int uid, float frameRate); + oneway void updateSmallAreaDetection(in int[] uids, in float[] thresholds); + + /** + * Set the small area detection threshold for a specified uid by SmallAreaDetectionController. + * Passing the threshold and uid to SurfaceFlinger to update the uid-threshold mapping + * in the scheduler. + */ + oneway void setSmallAreaDetectionThreshold(int uid, float threshold); + /** * Enables or disables the frame rate overlay in the top left corner. * Requires root or android.permission.HARDWARE_TEST diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h index 2643fa7d68..177d5f89c9 100644 --- a/libs/gui/fuzzer/libgui_fuzzer_utils.h +++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h @@ -154,6 +154,9 @@ public: MOCK_METHOD(binder::Status, setDebugFlash, (int), (override)); MOCK_METHOD(binder::Status, scheduleComposite, (), (override)); MOCK_METHOD(binder::Status, scheduleCommit, (), (override)); + MOCK_METHOD(binder::Status, updateSmallAreaDetection, + (const std::vector&, const std::vector&), (override)); + MOCK_METHOD(binder::Status, setSmallAreaDetectionThreshold, (int32_t, float), (override)); MOCK_METHOD(binder::Status, getGpuContextPriority, (int32_t*), (override)); MOCK_METHOD(binder::Status, getMaxAcquiredBufferCount, (int32_t*), (override)); MOCK_METHOD(binder::Status, addWindowInfosListener, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index fd9f186663..6fef5d2378 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -203,6 +203,16 @@ public: // by GameManager. static status_t setOverrideFrameRate(uid_t uid, float frameRate); + // Update the small area detection whole uid-threshold mappings by same size uid and threshold + // vector. + // Ref:setSmallAreaDetectionThreshold. + static status_t updateSmallAreaDetection(std::vector& uids, + std::vector& thresholds); + + // Sets the small area detection threshold to particular apps (uid). Passing value 0 means + // to disable small area detection to the app. + static status_t setSmallAreaDetectionThreshold(uid_t uid, float threshold); + // 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 // #getAutoLowLatencyModeSupport diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index ffb8622f39..daed764cd6 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -999,6 +999,15 @@ public: binder::Status scheduleCommit() override { return binder::Status::ok(); } + binder::Status updateSmallAreaDetection(const std::vector& /*uids*/, + const std::vector& /*thresholds*/) { + return binder::Status::ok(); + } + + binder::Status setSmallAreaDetectionThreshold(int32_t /*uid*/, float /*threshold*/) { + return binder::Status::ok(); + } + binder::Status getGpuContextPriority(int32_t* /*outPriority*/) override { return binder::Status::ok(); } diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 0101c1712a..eda52bfcb5 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -187,6 +187,7 @@ filegroup { "Scheduler/MessageQueue.cpp", "Scheduler/RefreshRateSelector.cpp", "Scheduler/Scheduler.cpp", + "Scheduler/SmallAreaDetectionAllowMappings.cpp", "Scheduler/VSyncDispatchTimerQueue.cpp", "Scheduler/VSyncPredictor.cpp", "Scheduler/VSyncReactor.cpp", diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 8f785a044c..077ed674ad 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -4388,7 +4388,8 @@ void Layer::setIsSmallDirty() { // If the damage region is a small dirty, this could give the hint for the layer history that // it could suppress the heuristic rate when calculating. - mSmallDirty = mFlinger->mScheduler->isSmallDirtyArea(bounds.getWidth() * bounds.getHeight()); + mSmallDirty = mFlinger->mScheduler->isSmallDirtyArea(mOwnerUid, + bounds.getWidth() * bounds.getHeight()); } } // namespace android diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 13cf764746..c92e670aa9 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -306,9 +306,9 @@ auto LayerHistory::findLayer(int32_t id) -> std::pair { return {LayerStatus::NotFound, nullptr}; } -bool LayerHistory::isSmallDirtyArea(uint32_t dirtyArea) const { +bool LayerHistory::isSmallDirtyArea(uint32_t dirtyArea, float threshold) const { const float ratio = (float)dirtyArea / mDisplayArea; - const bool isSmallDirty = ratio <= kSmallDirtyArea; + const bool isSmallDirty = ratio <= threshold; ATRACE_FORMAT_INSTANT("small dirty=%s, ratio=%.3f", isSmallDirty ? "true" : "false", ratio); return isSmallDirty; } diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index 562bb4cace..5750ea7898 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -85,14 +85,12 @@ public: // return the frames per second of the layer with the given sequence id. float getLayerFramerate(nsecs_t now, int32_t id) const; - bool isSmallDirtyArea(uint32_t dirtyArea) const; + bool isSmallDirtyArea(uint32_t dirtyArea, float threshold) const; private: friend class LayerHistoryTest; friend class TestableScheduler; - static constexpr float kSmallDirtyArea = 0.07f; - using LayerPair = std::pair>; // keyed by id as returned from Layer::getSequence() using LayerInfos = std::unordered_map; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 5a19ec5095..27c96f7d4f 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -1179,4 +1179,20 @@ void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverrid mFrameRateOverrideMappings.setPreferredRefreshRateForUid(frameRateOverride); } +void Scheduler::updateSmallAreaDetection( + std::vector>& uidThresholdMappings) { + mSmallAreaDetectionAllowMappings.update(uidThresholdMappings); +} + +void Scheduler::setSmallAreaDetectionThreshold(uid_t uid, float threshold) { + mSmallAreaDetectionAllowMappings.setThesholdForUid(uid, threshold); +} + +bool Scheduler::isSmallDirtyArea(uid_t uid, uint32_t dirtyArea) { + std::optional oThreshold = mSmallAreaDetectionAllowMappings.getThresholdForUid(uid); + if (oThreshold) return mLayerHistory.isSmallDirtyArea(dirtyArea, oThreshold.value()); + + return false; +} + } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index ec20610f81..d65df2a65d 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -49,6 +49,7 @@ #include "MessageQueue.h" #include "OneShotTimer.h" #include "RefreshRateSelector.h" +#include "SmallAreaDetectionAllowMappings.h" #include "Utils/Dumper.h" #include "VsyncModulator.h" @@ -291,6 +292,13 @@ public: void setGameModeRefreshRateForUid(FrameRateOverride); + void updateSmallAreaDetection(std::vector>& uidThresholdMappings); + + void setSmallAreaDetectionThreshold(uid_t uid, float threshold); + + // Returns true if the dirty area is less than threshold. + bool isSmallDirtyArea(uid_t uid, uint32_t dirtyArea); + // Retrieves the overridden refresh rate for a given uid. std::optional getFrameRateOverride(uid_t) const EXCLUDES(mDisplayLock); @@ -314,11 +322,6 @@ public: return mFeatures.test(Feature::kSmallDirtyContentDetection); } - // Returns true if the dirty area is less than threshold. - bool isSmallDirtyArea(uint32_t dirtyArea) const { - return mLayerHistory.isSmallDirtyArea(dirtyArea); - } - private: friend class TestableScheduler; @@ -557,6 +560,7 @@ private: static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms; FrameRateOverrideMappings mFrameRateOverrideMappings; + SmallAreaDetectionAllowMappings mSmallAreaDetectionAllowMappings; }; } // namespace scheduler diff --git a/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp new file mode 100644 index 0000000000..95cd5d199a --- /dev/null +++ b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp @@ -0,0 +1,47 @@ +/* + * Copyright 2023 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 + +#include "SmallAreaDetectionAllowMappings.h" + +namespace android::scheduler { +void SmallAreaDetectionAllowMappings::update( + std::vector>& uidThresholdMappings) { + std::lock_guard lock(mLock); + mMap.clear(); + for (std::pair row : uidThresholdMappings) { + if (!isValidThreshold(row.second)) continue; + + mMap.emplace(row.first, row.second); + } +} + +void SmallAreaDetectionAllowMappings::setThesholdForUid(uid_t uid, float threshold) { + if (!isValidThreshold(threshold)) return; + + std::lock_guard lock(mLock); + mMap.emplace(uid, threshold); +} + +std::optional SmallAreaDetectionAllowMappings::getThresholdForUid(uid_t uid) { + std::lock_guard lock(mLock); + const auto iter = mMap.find(uid); + if (iter != mMap.end()) { + return iter->second; + } + return std::nullopt; +} +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h new file mode 100644 index 0000000000..cbab69091f --- /dev/null +++ b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h @@ -0,0 +1,39 @@ +/* + * Copyright 2023 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 +#include +#include +#include +#include + +namespace android::scheduler { +class SmallAreaDetectionAllowMappings { + using UidThresholdMap = std::unordered_map; + +public: + void update(std::vector>& uidThresholdMappings); + void setThesholdForUid(uid_t uid, float threshold) EXCLUDES(mLock); + std::optional getThresholdForUid(uid_t uid) EXCLUDES(mLock); + +private: + static bool isValidThreshold(float threshold) { return threshold >= 0.0f && threshold <= 1.0f; } + mutable std::mutex mLock; + UidThresholdMap mMap GUARDED_BY(mLock); +}; +} // namespace android::scheduler diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 940a4c6b66..bc626f3030 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -8200,6 +8200,17 @@ status_t SurfaceFlinger::setOverrideFrameRate(uid_t uid, float frameRate) { return NO_ERROR; } +status_t SurfaceFlinger::updateSmallAreaDetection( + std::vector>& uidThresholdMappings) { + mScheduler->updateSmallAreaDetection(uidThresholdMappings); + return NO_ERROR; +} + +status_t SurfaceFlinger::setSmallAreaDetectionThreshold(uid_t uid, float threshold) { + mScheduler->setSmallAreaDetectionThreshold(uid, threshold); + return NO_ERROR; +} + void SurfaceFlinger::enableRefreshRateOverlay(bool enable) { bool setByHwc = getHwComposer().hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG); for (const auto& [id, display] : mPhysicalDisplays) { @@ -9532,6 +9543,40 @@ binder::Status SurfaceComposerAIDL::scheduleCommit() { return binder::Status::ok(); } +binder::Status SurfaceComposerAIDL::updateSmallAreaDetection(const std::vector& uids, + const std::vector& thresholds) { + status_t status; + const int c_uid = IPCThreadState::self()->getCallingUid(); + if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) { + if (uids.size() != thresholds.size()) return binderStatusFromStatusT(BAD_VALUE); + + std::vector> mappings; + const size_t size = uids.size(); + mappings.reserve(size); + for (int i = 0; i < size; i++) { + auto row = std::make_pair(static_cast(uids[i]), thresholds[i]); + mappings.push_back(row); + } + status = mFlinger->updateSmallAreaDetection(mappings); + } else { + ALOGE("updateSmallAreaDetection() permission denied for uid: %d", c_uid); + status = PERMISSION_DENIED; + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::setSmallAreaDetectionThreshold(int32_t uid, float threshold) { + status_t status; + const int c_uid = IPCThreadState::self()->getCallingUid(); + if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) { + status = mFlinger->setSmallAreaDetectionThreshold(uid, threshold); + } else { + ALOGE("setSmallAreaDetectionThreshold() permission denied for uid: %d", c_uid); + status = PERMISSION_DENIED; + } + return binderStatusFromStatusT(status); +} + binder::Status SurfaceComposerAIDL::getGpuContextPriority(int32_t* outPriority) { *outPriority = mFlinger->getGpuContextPriority(); return binder::Status::ok(); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6ff9fd1111..79dcd0d1b2 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -607,6 +607,10 @@ private: status_t setOverrideFrameRate(uid_t uid, float frameRate); + status_t updateSmallAreaDetection(std::vector>& uidThresholdMappings); + + status_t setSmallAreaDetectionThreshold(uid_t uid, float threshold); + int getGpuContextPriority(); status_t getMaxAcquiredBufferCount(int* buffers) const; @@ -1557,6 +1561,9 @@ public: binder::Status setDebugFlash(int delay) override; binder::Status scheduleComposite() override; binder::Status scheduleCommit() override; + binder::Status updateSmallAreaDetection(const std::vector& uids, + const std::vector& thresholds) override; + binder::Status setSmallAreaDetectionThreshold(int32_t uid, float threshold) override; binder::Status getGpuContextPriority(int32_t* outPriority) override; binder::Status getMaxAcquiredBufferCount(int32_t* buffers) override; binder::Status addWindowInfosListener(const sp& windowInfosListener, diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 7d8796f71c..8deff85118 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -101,6 +101,7 @@ cc_test { "LayerTestUtils.cpp", "MessageQueueTest.cpp", "PowerAdvisorTest.cpp", + "SmallAreaDetectionAllowMappingsTest.cpp", "SurfaceFlinger_CreateDisplayTest.cpp", "SurfaceFlinger_DestroyDisplayTest.cpp", "SurfaceFlinger_DisplayModeSwitching.cpp", diff --git a/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp b/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp new file mode 100644 index 0000000000..b910485c06 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp @@ -0,0 +1,61 @@ +/* + * Copyright 2023 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. + */ + +#undef LOG_TAG +#define LOG_TAG "SmallAreaDetectionAllowMappingsTest" + +#include + +#include "Scheduler/SmallAreaDetectionAllowMappings.h" + +namespace android::scheduler { + +class SmallAreaDetectionMappingsAllowTest : public testing::Test { +protected: + SmallAreaDetectionAllowMappings mMappings; +}; + +namespace { +TEST_F(SmallAreaDetectionMappingsAllowTest, testUpdate) { + const uid_t uid1 = 10100; + const uid_t uid2 = 10101; + const float threshold1 = 0.05f; + const float threshold2 = 0.07f; + std::vector> mappings; + mappings.reserve(2); + mappings.push_back(std::make_pair(uid1, threshold1)); + mappings.push_back(std::make_pair(uid2, threshold2)); + + mMappings.update(mappings); + ASSERT_EQ(mMappings.getThresholdForUid(uid1).value(), threshold1); + ASSERT_EQ(mMappings.getThresholdForUid(uid2).value(), threshold2); +} + +TEST_F(SmallAreaDetectionMappingsAllowTest, testSetThesholdForUid) { + const uid_t uid = 10111; + const float threshold = 0.05f; + + mMappings.setThesholdForUid(uid, threshold); + ASSERT_EQ(mMappings.getThresholdForUid(uid), threshold); +} + +TEST_F(SmallAreaDetectionMappingsAllowTest, testUidNotInTheMappings) { + const uid_t uid = 10222; + ASSERT_EQ(mMappings.getThresholdForUid(uid), std::nullopt); +} + +} // namespace +} // namespace android::scheduler -- cgit v1.2.3-59-g8ed1b From 6cdd3fd7dab0149041ee8dd7273fe83888d2b1e3 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 7 Sep 2023 18:45:58 -0700 Subject: libgui: plumb setFrameRate thru BufferQueue The current implementation just assumes that the Surface and BLASTBufferQueue lives in the same process and rely on inheritance to handle setFrameRate. This doesn't work for any usecase that the Surface is Parceled to a diffrent process. Bug: 281695725 Test: atest CtsGraphicsTestCases --test-filter SetFrameRateTest* Change-Id: I4e08b92b618fa7b863ca3ef4f7b46d9f1c30c775 --- libs/gui/Android.bp | 53 ++++++++++------ libs/gui/BLASTBufferQueue.cpp | 19 ++++++ libs/gui/BufferQueue.cpp | 11 ++++ libs/gui/BufferQueueProducer.cpp | 25 ++++++++ libs/gui/FrameRateUtils.cpp | 65 +++++++++++++++++++ libs/gui/IGraphicBufferProducer.cpp | 40 +++++++++++- libs/gui/LayerState.cpp | 29 +-------- libs/gui/Surface.cpp | 22 ++++++- libs/gui/SurfaceComposerClient.cpp | 1 + libs/gui/include/gui/BLASTBufferQueue.h | 9 ++- libs/gui/include/gui/BufferQueue.h | 7 +- libs/gui/include/gui/BufferQueueProducer.h | 6 ++ libs/gui/include/gui/Flags.h | 22 +++++++ libs/gui/include/gui/FrameRateUtils.h | 26 ++++++++ libs/gui/include/gui/IConsumerListener.h | 8 +++ libs/gui/include/gui/IGraphicBufferProducer.h | 7 ++ libs/gui/include/gui/LayerState.h | 10 --- libs/gui/tests/Android.bp | 22 +++---- libs/gui/tests/BufferQueue_test.cpp | 29 +++++++++ libs/gui/tests/FrameRateUtilsTest.cpp | 74 ++++++++++++++++++++++ .../tests/unittests/SetFrameRateTest.cpp | 43 +------------ 21 files changed, 408 insertions(+), 120 deletions(-) create mode 100644 libs/gui/FrameRateUtils.cpp create mode 100644 libs/gui/include/gui/Flags.h create mode 100644 libs/gui/include/gui/FrameRateUtils.h create mode 100644 libs/gui/tests/FrameRateUtilsTest.cpp (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 2ea4d16260..9a27d2321b 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -204,27 +204,8 @@ cc_aconfig_library { aconfig_declarations: "libgui_flags", } -cc_library_shared { - name: "libgui", - vendor_available: true, - vndk: { - enabled: true, - private: true, - }, - double_loadable: true, - - defaults: ["libgui_bufferqueue-defaults"], - - static_libs: [ - "libgui_aidl_static", - "libgui_window_info_static", - "libguiflags", - ], - export_static_lib_headers: [ - "libgui_aidl_static", - "libgui_window_info_static", - ], - +filegroup { + name: "libgui-sources", srcs: [ ":framework_native_aidl_binder", ":framework_native_aidl_gui", @@ -268,11 +249,40 @@ cc_library_shared { "bufferqueue/2.0/B2HProducerListener.cpp", "bufferqueue/2.0/H2BGraphicBufferProducer.cpp", ], +} +cc_defaults { + name: "libgui-defaults", + defaults: ["libgui_bufferqueue-defaults"], + srcs: [":libgui-sources"], + static_libs: [ + "libgui_aidl_static", + "libgui_window_info_static", + "libguiflags", + ], shared_libs: [ "libbinder", "libGLESv2", ], +} + +cc_library_shared { + name: "libgui", + vendor_available: true, + vndk: { + enabled: true, + private: true, + }, + double_loadable: true, + + defaults: [ + "libgui-defaults", + ], + + export_static_lib_headers: [ + "libgui_aidl_static", + "libgui_window_info_static", + ], export_shared_lib_headers: [ "libbinder", @@ -346,6 +356,7 @@ filegroup { "BufferQueueProducer.cpp", "BufferQueueThreadState.cpp", "BufferSlot.cpp", + "FrameRateUtils.cpp", "FrameTimestamps.cpp", "GLConsumerUtils.cpp", "HdrMetadata.cpp", diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 207fa4fd31..dd0a028865 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -39,6 +41,9 @@ #include #include +#include + +using namespace com::android::graphics::libgui; using namespace std::chrono_literals; namespace { @@ -139,6 +144,16 @@ void BLASTBufferItemConsumer::onSidebandStreamChanged() { } } +#if FLAG_BQ_SET_FRAME_RATE +void BLASTBufferItemConsumer::onSetFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) { + sp bbq = mBLASTBufferQueue.promote(); + if (bbq != nullptr) { + bbq->setFrameRate(frameRate, compatibility, changeFrameRateStrategy); + } +} +#endif + void BLASTBufferItemConsumer::resizeFrameEventHistory(size_t newSize) { Mutex::Autolock lock(mMutex); mFrameEventHistory.resize(newSize); @@ -890,6 +905,10 @@ public: status_t setFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) override { + if (flags::bq_setframerate()) { + return Surface::setFrameRate(frameRate, compatibility, changeFrameRateStrategy); + } + std::lock_guard _lock{mMutex}; if (mDestroyed) { return DEAD_OBJECT; diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 66cad03fec..ab0f6d213f 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -22,6 +22,7 @@ #include #include #include +#include namespace android { @@ -98,6 +99,16 @@ void BufferQueue::ProxyConsumerListener::addAndGetFrameTimestamps( } } +#if FLAG_BQ_SET_FRAME_RATE +void BufferQueue::ProxyConsumerListener::onSetFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) { + sp listener(mConsumerListener.promote()); + if (listener != nullptr) { + listener->onSetFrameRate(frameRate, compatibility, changeFrameRateStrategy); + } +} +#endif + void BufferQueue::createBufferQueue(sp* outProducer, sp* outConsumer, bool consumerIsSurfaceFlinger) { diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 920b83dba9..67dff6dec6 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include #include @@ -1751,4 +1753,27 @@ status_t BufferQueueProducer::setAutoPrerotation(bool autoPrerotation) { return NO_ERROR; } +#if FLAG_BQ_SET_FRAME_RATE +status_t BufferQueueProducer::setFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) { + ATRACE_CALL(); + BQ_LOGV("setFrameRate: %.2f", frameRate); + + if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy, + "BufferQueueProducer::setFrameRate")) { + return BAD_VALUE; + } + + sp listener; + { + std::lock_guard lock(mCore->mMutex); + listener = mCore->mConsumerListener; + } + if (listener != nullptr) { + listener->onSetFrameRate(frameRate, compatibility, changeFrameRateStrategy); + } + return NO_ERROR; +} +#endif + } // namespace android diff --git a/libs/gui/FrameRateUtils.cpp b/libs/gui/FrameRateUtils.cpp new file mode 100644 index 0000000000..6993bfab45 --- /dev/null +++ b/libs/gui/FrameRateUtils.cpp @@ -0,0 +1,65 @@ +/* + * Copyright 2023 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 +#include +#include +#include + +#include + +namespace android { +// Returns true if the frameRate is valid. +// +// @param frameRate the frame rate in Hz +// @param compatibility a ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* +// @param changeFrameRateStrategy a ANATIVEWINDOW_CHANGE_FRAME_RATE_* +// @param functionName calling function or nullptr. Used for logging +// @param privileged whether caller has unscoped surfaceflinger access +bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy, + const char* inFunctionName, bool privileged) { + const char* functionName = inFunctionName != nullptr ? inFunctionName : "call"; + int floatClassification = std::fpclassify(frameRate); + if (frameRate < 0 || floatClassification == FP_INFINITE || floatClassification == FP_NAN) { + ALOGE("%s failed - invalid frame rate %f", functionName, frameRate); + return false; + } + + if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT && + compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE && + (!privileged || + (compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT && + compatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE))) { + ALOGE("%s failed - invalid compatibility value %d privileged: %s", functionName, + compatibility, privileged ? "yes" : "no"); + return false; + } + + if (__builtin_available(android 31, *)) { + if (changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS && + changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS) { + ALOGE("%s failed - invalid change frame rate strategy value %d", functionName, + changeFrameRateStrategy); + if (FLAG_BQ_SET_FRAME_RATE) { + return false; + } + } + } + + return true; +} + +} // namespace android diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 918ff2dd25..d0c09e481d 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -27,11 +27,12 @@ #include #include -#include -#include #include +#include #include #include +#include +#include namespace android { // ---------------------------------------------------------------------------- @@ -78,6 +79,7 @@ enum { CANCEL_BUFFERS, QUERY_MULTIPLE, GET_LAST_QUEUED_BUFFER2, + SET_FRAME_RATE, }; class BpGraphicBufferProducer : public BpInterface @@ -761,6 +763,21 @@ public: } return result; } +#if FLAG_BQ_SET_FRAME_RATE + virtual status_t setFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) override { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeFloat(frameRate); + data.writeInt32(compatibility); + data.writeInt32(changeFrameRateStrategy); + status_t result = remote()->transact(SET_FRAME_RATE, data, &reply); + if (result == NO_ERROR) { + result = reply.readInt32(); + } + return result; + } +#endif }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -956,6 +973,14 @@ status_t IGraphicBufferProducer::setAutoPrerotation(bool autoPrerotation) { return INVALID_OPERATION; } +#if FLAG_BQ_SET_FRAME_RATE +status_t IGraphicBufferProducer::setFrameRate(float /*frameRate*/, int8_t /*compatibility*/, + int8_t /*changeFrameRateStrategy*/) { + // No-op for IGBP other than BufferQueue. + return INVALID_OPERATION; +} +#endif + status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) { status_t res = OK; res = parcel->writeUint32(USE_BUFFER_QUEUE); @@ -1497,6 +1522,17 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(result); return NO_ERROR; } +#if FLAG_BQ_SET_FRAME_RATE + case SET_FRAME_RATE: { + CHECK_INTERFACE(IGraphicBuffer, data, reply); + float frameRate = data.readFloat(); + int8_t compatibility = data.readInt32(); + int8_t changeFrameRateStrategy = data.readInt32(); + status_t result = setFrameRate(frameRate, compatibility, changeFrameRateStrategy); + reply->writeInt32(result); + return NO_ERROR; + } +#endif } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index e1afb524e7..9847c056b8 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -863,34 +864,6 @@ status_t InputWindowCommands::read(const Parcel& input) { return NO_ERROR; } -bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy, - const char* inFunctionName, bool privileged) { - const char* functionName = inFunctionName != nullptr ? inFunctionName : "call"; - int floatClassification = std::fpclassify(frameRate); - if (frameRate < 0 || floatClassification == FP_INFINITE || floatClassification == FP_NAN) { - ALOGE("%s failed - invalid frame rate %f", functionName, frameRate); - return false; - } - - if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT && - compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE && - (!privileged || - (compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT && - compatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE))) { - ALOGE("%s failed - invalid compatibility value %d privileged: %s", functionName, - compatibility, privileged ? "yes" : "no"); - return false; - } - - if (changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS && - changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS) { - ALOGE("%s failed - invalid change frame rate strategy value %d", functionName, - changeFrameRateStrategy); - } - - return true; -} - // ---------------------------------------------------------------------------- namespace gui { diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 53a2f64d11..a87f05357f 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -43,6 +43,7 @@ #include #include +#include #include #include @@ -50,8 +51,11 @@ #include #include +#include + namespace android { +using namespace com::android::graphics::libgui; using gui::aidl_utils::statusTFromBinderStatus; using ui::Dataspace; @@ -2565,8 +2569,22 @@ void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vectoronBuffersDiscarded(discardedBufs); } -[[deprecated]] status_t Surface::setFrameRate(float /*frameRate*/, int8_t /*compatibility*/, - int8_t /*changeFrameRateStrategy*/) { +status_t Surface::setFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) { +#if FLAG_BQ_SET_FRAME_RATE + if (flags::bq_setframerate()) { + status_t err = mGraphicBufferProducer->setFrameRate(frameRate, compatibility, + changeFrameRateStrategy); + ALOGE_IF(err, "IGraphicBufferProducer::setFrameRate(%.2f) returned %s", frameRate, + strerror(-err)); + return err; + } +#else + static_cast(frameRate); + static_cast(compatibility); + static_cast(changeFrameRateStrategy); +#endif + ALOGI("Surface::setFrameRate is deprecated, setFrameRate hint is dropped as destination is not " "SurfaceFlinger"); // ISurfaceComposer no longer supports setFrameRate, we will return NO_ERROR when the api is diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 4db960e7fa..e0882ac6bb 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index a49a85984f..02d7c4d2ac 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -17,9 +17,10 @@ #ifndef ANDROID_GUI_BLAST_BUFFER_QUEUE_H #define ANDROID_GUI_BLAST_BUFFER_QUEUE_H -#include -#include #include +#include +#include +#include #include #include @@ -58,6 +59,10 @@ public: protected: void onSidebandStreamChanged() override EXCLUDES(mMutex); +#if FLAG_BQ_SET_FRAME_RATE + void onSetFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) override; +#endif private: const wp mBLASTBufferQueue; diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h index 690587f0e6..2756277f2c 100644 --- a/libs/gui/include/gui/BufferQueue.h +++ b/libs/gui/include/gui/BufferQueue.h @@ -19,9 +19,10 @@ #include #include +#include +#include #include #include -#include namespace android { @@ -69,6 +70,10 @@ public: void addAndGetFrameTimestamps( const NewFrameEventsEntry* newTimestamps, FrameEventHistoryDelta* outDelta) override; +#if FLAG_BQ_SET_FRAME_RATE + void onSetFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) override; +#endif private: // mConsumerListener is a weak reference to the IConsumerListener. This is // the raison d'etre of ProxyConsumerListener. diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index 1d13dab623..38805d0221 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -18,6 +18,7 @@ #define ANDROID_GUI_BUFFERQUEUEPRODUCER_H #include +#include #include namespace android { @@ -201,6 +202,11 @@ public: // See IGraphicBufferProducer::setAutoPrerotation virtual status_t setAutoPrerotation(bool autoPrerotation); +#if FLAG_BQ_SET_FRAME_RATE + // See IGraphicBufferProducer::setFrameRate + status_t setFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) override; +#endif protected: // see IGraphicsBufferProducer::setMaxDequeuedBufferCount, but with the ability to retrieve the diff --git a/libs/gui/include/gui/Flags.h b/libs/gui/include/gui/Flags.h new file mode 100644 index 0000000000..a2cff56e97 --- /dev/null +++ b/libs/gui/include/gui/Flags.h @@ -0,0 +1,22 @@ +/* + * Copyright 2023 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 + +// TODO(281695725): replace this with build time flags, whenever they are available +#ifndef FLAG_BQ_SET_FRAME_RATE +#define FLAG_BQ_SET_FRAME_RATE false +#endif \ No newline at end of file diff --git a/libs/gui/include/gui/FrameRateUtils.h b/libs/gui/include/gui/FrameRateUtils.h new file mode 100644 index 0000000000..16896efe1f --- /dev/null +++ b/libs/gui/include/gui/FrameRateUtils.h @@ -0,0 +1,26 @@ +/* + * Copyright 2023 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 + +namespace android { + +bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy, + const char* inFunctionName, bool privileged = false); + +} // namespace android \ No newline at end of file diff --git a/libs/gui/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h index 0ab2399eb2..e183bf2668 100644 --- a/libs/gui/include/gui/IConsumerListener.h +++ b/libs/gui/include/gui/IConsumerListener.h @@ -19,6 +19,8 @@ #include #include +#include + #include #include @@ -90,6 +92,12 @@ public: // WARNING: This method can only be called when the BufferQueue is in the consumer's process. virtual void addAndGetFrameTimestamps(const NewFrameEventsEntry* /*newTimestamps*/, FrameEventHistoryDelta* /*outDelta*/) {} + +#if FLAG_BQ_SET_FRAME_RATE + // Notifies the consumer of a setFrameRate call from the producer side. + virtual void onSetFrameRate(float /*frameRate*/, int8_t /*compatibility*/, + int8_t /*changeFrameRateStrategy*/) {} +#endif }; #ifndef NO_BINDER diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 98df83453d..3562906870 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -676,6 +677,12 @@ public: // the width and height used for dequeueBuffer will be additionally swapped. virtual status_t setAutoPrerotation(bool autoPrerotation); +#if FLAG_BQ_SET_FRAME_RATE + // Sets the apps intended frame rate. + virtual status_t setFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy); +#endif + struct RequestBufferOutput : public Flattenable { RequestBufferOutput() = default; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 8c360589f0..102a3c1e25 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -476,16 +476,6 @@ static inline int compare_type(const DisplayState& lhs, const DisplayState& rhs) return compare_type(lhs.token, rhs.token); } -// Returns true if the frameRate is valid. -// -// @param frameRate the frame rate in Hz -// @param compatibility a ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* -// @param changeFrameRateStrategy a ANATIVEWINDOW_CHANGE_FRAME_RATE_* -// @param functionName calling function or nullptr. Used for logging -// @param privileged whether caller has unscoped surfaceflinger access -bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy, - const char* functionName, bool privileged = false); - }; // namespace android #endif // ANDROID_SF_LAYER_STATE_H diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 462ce6e14f..38c0eed474 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -15,9 +15,13 @@ cc_test { name: "libgui_test", test_suites: ["device-tests"], - cflags: [ + defaults: ["libgui-defaults"], + + cppflags: [ "-Wall", "-Werror", + "-Wno-extra", + "-DFLAG_BQ_SET_FRAME_RATE=true", ], srcs: [ @@ -28,6 +32,7 @@ cc_test { "CompositorTiming_test.cpp", "CpuConsumer_test.cpp", "EndToEndNativeInputTest.cpp", + "FrameRateUtilsTest.cpp", "DisplayInfo_test.cpp", "DisplayedContentSampling_test.cpp", "FillBuffer.cpp", @@ -53,19 +58,12 @@ cc_test { "android.hardware.configstore@1.0", "android.hardware.configstore-utils", "libSurfaceFlingerProp", - "libbase", - "liblog", - "libEGL", "libGLESv1_CM", - "libGLESv2", - "libbinder", - "libcutils", - "libgui", - "libhidlbase", "libinput", - "libui", - "libutils", - "libnativewindow", + ], + + static_libs: [ + "libgmock", ], header_libs: ["libsurfaceflinger_headers"], diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 0168877478..17aa5f1350 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -37,14 +37,18 @@ #include +#include #include #include #include +#include + using namespace std::chrono_literals; namespace android { +using namespace com::android::graphics::libgui; class BufferQueueTest : public ::testing::Test { @@ -1261,6 +1265,31 @@ TEST_F(BufferQueueTest, TestProducerConnectDisconnect) { ASSERT_EQ(NO_INIT, mProducer->disconnect(NATIVE_WINDOW_API_CPU)); } +TEST_F(BufferQueueTest, TestBqSetFrameRateFlagBuildTimeIsSet) { + if (flags::bq_setframerate()) { + ASSERT_EQ(true, FLAG_BQ_SET_FRAME_RATE); + } +} + +struct BufferItemConsumerSetFrameRateListener : public BufferItemConsumer { + BufferItemConsumerSetFrameRateListener(const sp& consumer) + : BufferItemConsumer(consumer, GRALLOC_USAGE_SW_READ_OFTEN, 1) {} + + MOCK_METHOD(void, onSetFrameRate, (float, int8_t, int8_t), (override)); +}; + +TEST_F(BufferQueueTest, TestSetFrameRate) { + sp producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp bufferConsumer = + sp::make(consumer); + + EXPECT_CALL(*bufferConsumer, onSetFrameRate(12.34f, 1, 0)).Times(1); + producer->setFrameRate(12.34f, 1, 0); +} + class Latch { public: explicit Latch(int expected) : mExpected(expected) {} diff --git a/libs/gui/tests/FrameRateUtilsTest.cpp b/libs/gui/tests/FrameRateUtilsTest.cpp new file mode 100644 index 0000000000..5fe22b05f9 --- /dev/null +++ b/libs/gui/tests/FrameRateUtilsTest.cpp @@ -0,0 +1,74 @@ +/* + * Copyright 2018 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 + +#include +#include +#include + +#include + +namespace android { +using namespace com::android::graphics::libgui; + +TEST(FrameRateUtilsTest, ValidateFrameRate) { + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + + // Privileged APIs. + EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_FALSE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + + constexpr bool kPrivileged = true; + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "", + kPrivileged)); + EXPECT_TRUE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "", + kPrivileged)); + + // Invalid frame rate. + EXPECT_FALSE(ValidateFrameRate(-1, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_FALSE(ValidateFrameRate(1.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_FALSE(ValidateFrameRate(0.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + + // Invalid compatibility. + EXPECT_FALSE( + ValidateFrameRate(60.0f, -1, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_FALSE(ValidateFrameRate(60.0f, 2, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + + // Invalid change frame rate strategy. + if (flags::bq_setframerate()) { + EXPECT_FALSE( + ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, -1, "")); + EXPECT_FALSE( + ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, 2, "")); + } +} + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 608fa762ef..9899d4290b 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -19,6 +19,7 @@ #include #include +#include #include // TODO(b/129481165): remove the #pragma below and fix conversion issues @@ -325,48 +326,6 @@ INSTANTIATE_TEST_SUITE_P(PerLayerType, SetFrameRateTest, std::make_shared()), PrintToStringParamName); -TEST_F(SetFrameRateTest, ValidateFrameRate) { - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS, "")); - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - - // Privileged APIs. - EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - EXPECT_FALSE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - - constexpr bool kPrivileged = true; - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "", - kPrivileged)); - EXPECT_TRUE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "", - kPrivileged)); - - // Invalid frame rate. - EXPECT_FALSE(ValidateFrameRate(-1, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - EXPECT_FALSE(ValidateFrameRate(1.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - EXPECT_FALSE(ValidateFrameRate(0.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - - // Invalid compatibility. - EXPECT_FALSE( - ValidateFrameRate(60.0f, -1, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - EXPECT_FALSE(ValidateFrameRate(60.0f, 2, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - - // Invalid change frame rate strategy. - EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, -1, "")); - EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, 2, "")); -} - TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { const auto& layerFactory = GetParam(); -- cgit v1.2.3-59-g8ed1b From 58cc90d352b71bd1be16d4a89053350bbeada0af Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Tue, 5 Sep 2023 18:50:20 -0700 Subject: Plumb new frameRateSelectionStrategy value This new value will allow a parent layer to override the frame rate specifications of all its descendants. This CL only plumbs the value from Transaction to Layer. Bug: 297418260 Test: atest CtsSurfaceControlTestsStaging Test: atest libsurfaceflinger_unittest Change-Id: Ibbda6ff6c143e931240178d89306822b4cce9669 --- libs/gui/LayerState.cpp | 8 ++++ libs/gui/SurfaceComposerClient.cpp | 13 +++++++ libs/gui/include/gui/LayerState.h | 6 ++- libs/gui/include/gui/SurfaceComposerClient.h | 2 + libs/nativewindow/include/system/window.h | 20 ++++++++++ services/surfaceflinger/FrontEnd/LayerSnapshot.h | 1 + .../FrontEnd/LayerSnapshotBuilder.cpp | 16 +++++++- .../FrontEnd/RequestedLayerState.cpp | 2 + services/surfaceflinger/Layer.cpp | 10 +++++ services/surfaceflinger/Layer.h | 5 +++ services/surfaceflinger/Scheduler/LayerInfo.cpp | 13 +++++++ services/surfaceflinger/Scheduler/LayerInfo.h | 15 +++++++- services/surfaceflinger/SurfaceFlinger.cpp | 8 ++++ .../tests/unittests/LayerHierarchyTest.h | 12 ++++++ .../tests/unittests/LayerSnapshotTest.cpp | 44 ++++++++++++++++++++++ 15 files changed, 170 insertions(+), 5 deletions(-) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index e1afb524e7..27b1d8b09b 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -84,6 +84,7 @@ layer_state_t::layer_state_t() changeFrameRateStrategy(ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS), defaultFrameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), frameRateCategory(ANATIVEWINDOW_FRAME_RATE_CATEGORY_DEFAULT), + frameRateSelectionStrategy(ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF), fixedTransformHint(ui::Transform::ROT_INVALID), autoRefresh(false), isTrustedOverlay(false), @@ -160,6 +161,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeByte, changeFrameRateStrategy); SAFE_PARCEL(output.writeByte, defaultFrameRateCompatibility); SAFE_PARCEL(output.writeByte, frameRateCategory); + SAFE_PARCEL(output.writeByte, frameRateSelectionStrategy); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeBool, autoRefresh); SAFE_PARCEL(output.writeBool, dimmingEnabled); @@ -293,6 +295,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readByte, &changeFrameRateStrategy); SAFE_PARCEL(input.readByte, &defaultFrameRateCompatibility); SAFE_PARCEL(input.readByte, &frameRateCategory); + SAFE_PARCEL(input.readByte, &frameRateSelectionStrategy); SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); SAFE_PARCEL(input.readBool, &autoRefresh); @@ -666,6 +669,10 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eFrameRateCategoryChanged; frameRateCategory = other.frameRateCategory; } + if (other.what & eFrameRateSelectionStrategyChanged) { + what |= eFrameRateSelectionStrategyChanged; + frameRateSelectionStrategy = other.frameRateSelectionStrategy; + } if (other.what & eFixedTransformHintChanged) { what |= eFixedTransformHintChanged; fixedTransformHint = other.fixedTransformHint; @@ -777,6 +784,7 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const { CHECK_DIFF3(diff, eFrameRateChanged, other, frameRate, frameRateCompatibility, changeFrameRateStrategy); CHECK_DIFF(diff, eFrameRateCategoryChanged, other, frameRateCategory); + CHECK_DIFF(diff, eFrameRateSelectionStrategyChanged, other, frameRateSelectionStrategy); CHECK_DIFF(diff, eFixedTransformHintChanged, other, fixedTransformHint); CHECK_DIFF(diff, eAutoRefreshChanged, other, autoRefresh); CHECK_DIFF(diff, eTrustedOverlayChanged, other, isTrustedOverlay); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 4db960e7fa..c2543d182b 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2104,6 +2104,19 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame return *this; } +SurfaceComposerClient::Transaction& +SurfaceComposerClient::Transaction::setFrameRateSelectionStrategy(const sp& sc, + int8_t strategy) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eFrameRateSelectionStrategyChanged; + s->frameRateSelectionStrategy = strategy; + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixedTransformHint( const sp& sc, int32_t fixedTransformHint) { layer_state_t* s = getLayerState(sc); diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 8c360589f0..35fcccdf78 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -197,7 +197,7 @@ struct layer_state_t { eInputInfoChanged = 0x40000000, eCornerRadiusChanged = 0x80000000, eDestinationFrameChanged = 0x1'00000000, - /* unused = 0x2'00000000, */ + eFrameRateSelectionStrategyChanged = 0x2'00000000, eBackgroundColorChanged = 0x4'00000000, eMetadataChanged = 0x8'00000000, eColorSpaceAgnosticChanged = 0x10'00000000, @@ -268,6 +268,7 @@ struct layer_state_t { layer_state_t::eColorTransformChanged | layer_state_t::eCornerRadiusChanged | layer_state_t::eFlagsChanged | layer_state_t::eTrustedOverlayChanged | layer_state_t::eFrameRateChanged | layer_state_t::eFrameRateCategoryChanged | + layer_state_t::eFrameRateSelectionStrategyChanged | layer_state_t::eFrameRateSelectionPriority | layer_state_t::eFixedTransformHintChanged; // Changes affecting data sent to input. @@ -361,6 +362,9 @@ struct layer_state_t { // Frame rate category to suggest what frame rate range a surface should run. int8_t frameRateCategory; + // Strategy of the layer for frame rate selection. + int8_t frameRateSelectionStrategy; + // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that // the graphic producers should receive a transform hint as if the diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 6fef5d2378..42e3c164ed 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -687,6 +687,8 @@ public: Transaction& setFrameRateCategory(const sp& sc, int8_t category); + Transaction& setFrameRateSelectionStrategy(const sp& sc, int8_t strategy); + // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that // the graphic producers should receive a transform hint as if the diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index e158f01e8c..b068f4807c 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1096,6 +1096,26 @@ enum { ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH = 4 }; +/* + * Frame rate selection strategy values that can be used in + * Transaction::setFrameRateSelectionStrategy. + */ +enum { + /** + * Default value. The layer uses its own frame rate specifications, assuming it has any + * specifications, instead of its parent's. + */ + ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF = 0, + + /** + * The layer's frame rate specifications will propagate to and override those of its descendant + * layers. + * The layer with this strategy has the ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF + * behavior for itself. + */ + ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN = 1, +}; + static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) { return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate, diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h index 7537a39060..a5e9368565 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h @@ -85,6 +85,7 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { bool isTrustedOverlay; gui::GameMode gameMode; scheduler::LayerInfo::FrameRate frameRate; + scheduler::LayerInfo::FrameRateSelectionStrategy frameRateSelectionStrategy; ui::Transform::RotationFlags fixedTransformHint; std::optional transformHint; bool handleSkipScreenshotFlag = false; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index da84e44085..4c9fb0655b 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -813,11 +813,23 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a RequestedLayerState::Changes::Hierarchy) || snapshot.changes.any(RequestedLayerState::Changes::FrameRate | RequestedLayerState::Changes::Hierarchy)) { - snapshot.frameRate = requested.requestedFrameRate.isValid() ? requested.requestedFrameRate - : parentSnapshot.frameRate; + bool shouldOverrideChildren = parentSnapshot.frameRateSelectionStrategy == + scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren; + snapshot.frameRate = !requested.requestedFrameRate.isValid() || shouldOverrideChildren + ? parentSnapshot.frameRate + : requested.requestedFrameRate; snapshot.changes |= RequestedLayerState::Changes::FrameRate; } + if (forceUpdate || snapshot.clientChanges & layer_state_t::eFrameRateSelectionStrategyChanged) { + const auto strategy = scheduler::LayerInfo::convertFrameRateSelectionStrategy( + requested.frameRateSelectionStrategy); + snapshot.frameRateSelectionStrategy = + strategy == scheduler::LayerInfo::FrameRateSelectionStrategy::Self + ? parentSnapshot.frameRateSelectionStrategy + : strategy; + } + if (forceUpdate || snapshot.clientChanges & layer_state_t::eFrameRateSelectionPriority) { snapshot.frameRateSelectionPriority = (requested.frameRateSelectionPriority == Layer::PRIORITY_UNSET) diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index 57ebee92d4..acec630167 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -125,6 +125,8 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) defaultFrameRateCompatibility = static_cast(scheduler::LayerInfo::FrameRateCompatibility::Default); frameRateCategory = static_cast(FrameRateCategory::Default); + frameRateSelectionStrategy = + static_cast(scheduler::LayerInfo::FrameRateSelectionStrategy::Self); dataspace = ui::Dataspace::V0_SRGB; gameMode = gui::GameMode::Unsupported; requestedFrameRate = {}; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 26840005d4..31b5e28e4e 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -192,6 +192,7 @@ Layer::Layer(const surfaceflinger::LayerCreationArgs& args) mDrawingState.dropInputMode = gui::DropInputMode::NONE; mDrawingState.dimmingEnabled = true; mDrawingState.defaultFrameRateCompatibility = FrameRateCompatibility::Default; + mDrawingState.frameRateSelectionStrategy = FrameRateSelectionStrategy::Self; if (args.flags & ISurfaceComposerClient::eNoColorFill) { // Set an invalid color so there is no color fill. @@ -1338,6 +1339,15 @@ bool Layer::setFrameRateCategory(FrameRateCategory category) { return true; } +bool Layer::setFrameRateSelectionStrategy(FrameRateSelectionStrategy strategy) { + if (mDrawingState.frameRateSelectionStrategy == strategy) return false; + mDrawingState.frameRateSelectionStrategy = strategy; + mDrawingState.sequence++; + mDrawingState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + void Layer::setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info, nsecs_t postTime) { mDrawingState.postTime = postTime; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 0b0cef54bf..d5e2185a5e 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -112,6 +112,7 @@ public: using FrameRate = scheduler::LayerInfo::FrameRate; using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility; + using FrameRateSelectionStrategy = scheduler::LayerInfo::FrameRateSelectionStrategy; struct State { int32_t z; @@ -188,6 +189,8 @@ public: // The combined frame rate of parents / children of this layer FrameRate frameRateForLayerTree; + FrameRateSelectionStrategy frameRateSelectionStrategy; + // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that // the graphic producers should receive a transform hint as if the @@ -782,6 +785,8 @@ public: bool setFrameRate(FrameRate::FrameRateVote); bool setFrameRateCategory(FrameRateCategory); + bool setFrameRateSelectionStrategy(FrameRateSelectionStrategy); + virtual void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {} void setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info, nsecs_t postTime); void setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInfo& info, diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index 0784251dc6..03844ef183 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -490,6 +490,19 @@ FrameRateCategory LayerInfo::FrameRate::convertCategory(int8_t category) { } } +LayerInfo::FrameRateSelectionStrategy LayerInfo::convertFrameRateSelectionStrategy( + int8_t strategy) { + switch (strategy) { + case ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF: + return FrameRateSelectionStrategy::Self; + case ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_OVERRIDE_CHILDREN: + return FrameRateSelectionStrategy::OverrideChildren; + default: + LOG_ALWAYS_FATAL("Invalid frame rate selection strategy value %d", strategy); + return FrameRateSelectionStrategy::Self; + } +} + bool LayerInfo::FrameRate::isNoVote() const { return vote.type == FrameRateCompatibility::NoVote; } diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 7fe407f5f7..3b4d8239d2 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -96,6 +96,13 @@ public: ftl_last = NoVote }; + enum class FrameRateSelectionStrategy { + Self, + OverrideChildren, + + ftl_last = OverrideChildren + }; + // Encapsulates the frame rate specifications of the layer. This information will be used // when the display refresh rate is determined. struct FrameRate { @@ -139,11 +146,11 @@ public: static FrameRateCompatibility convertCompatibility(int8_t compatibility); // Convert an ANATIVEWINDOW_CHANGE_FRAME_RATE_* value to a scheduler::Seamlessness. - // Logs fatal if the compatibility value is invalid. + // Logs fatal if the strategy value is invalid. static scheduler::Seamlessness convertChangeFrameRateStrategy(int8_t strategy); // Convert an ANATIVEWINDOW_FRAME_RATE_CATEGORY_* value to a FrameRateCategory. - // Logs fatal if the compatibility value is invalid. + // Logs fatal if the category value is invalid. static FrameRateCategory convertCategory(int8_t category); // True if the FrameRate has explicit frame rate specifications. @@ -164,6 +171,10 @@ public: } }; + // Convert an ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_* value to FrameRateSelectionStrategy. + // Logs fatal if the strategy value is invalid. + static FrameRateSelectionStrategy convertFrameRateSelectionStrategy(int8_t strategy); + static void setTraceEnabled(bool enabled) { sTraceEnabled = enabled; } LayerInfo(const std::string& name, uid_t ownerUid, LayerHistory::LayerVoteType defaultVote); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6d4d186fd7..10768a9b0c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5206,6 +5206,14 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime flags |= eTraversalNeeded; } } + if (what & layer_state_t::eFrameRateSelectionStrategyChanged) { + const scheduler::LayerInfo::FrameRateSelectionStrategy strategy = + scheduler::LayerInfo::convertFrameRateSelectionStrategy( + s.frameRateSelectionStrategy); + if (layer->setFrameRateSelectionStrategy(strategy)) { + flags |= eTraversalNeeded; + } + } if (what & layer_state_t::eFixedTransformHintChanged) { if (layer->setFixedTransformHint(s.fixedTransformHint)) { flags |= eTraversalNeeded | eTransformHintUpdateNeeded; diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h index ff644ba9f1..32821b7891 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h @@ -346,6 +346,18 @@ protected: mLifecycleManager.applyTransactions(transactions); } + void setFrameRateSelectionStrategy(uint32_t id, int8_t strategy) { + std::vector transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + + transactions.back().states.front().state.what = + layer_state_t::eFrameRateSelectionStrategyChanged; + transactions.back().states.front().layerId = id; + transactions.back().states.front().state.frameRateSelectionStrategy = strategy; + mLifecycleManager.applyTransactions(transactions); + } + void setRoundedCorners(uint32_t id, float radius) { std::vector transactions; transactions.emplace_back(); diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 1227b994dd..662f4bd466 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -743,6 +743,50 @@ TEST_F(LayerSnapshotTest, frameRateWithCategory) { EXPECT_TRUE(getSnapshot({.id = 1221})->changes.test(RequestedLayerState::Changes::FrameRate)); } +TEST_F(LayerSnapshotTest, frameRateSelectionStrategy) { + // ROOT + // ├── 1 + // │ ├── 11 + // │ │ └── 111 + // │ ├── 12 (frame rate set to 244.f with strategy OverrideChildren) + // │ │ ├── 121 + // │ │ └── 122 (frame rate set to 123.f but should be overridden by layer 12) + // │ │ └── 1221 + // │ └── 13 + // └── 2 + setFrameRate(12, 244.f, 0, 0); + setFrameRate(122, 123.f, 0, 0); + setFrameRateSelectionStrategy(12, 1 /* OverrideChildren */); + + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + // verify parent 1 gets no vote + EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type, + scheduler::LayerInfo::FrameRateCompatibility::NoVote); + EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate)); + + // verify layer 12 and all descendants (121, 122, 1221) get the requested vote + EXPECT_EQ(getSnapshot({.id = 12})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 12})->frameRateSelectionStrategy, + scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren); + EXPECT_TRUE(getSnapshot({.id = 12})->changes.test(RequestedLayerState::Changes::FrameRate)); + + EXPECT_EQ(getSnapshot({.id = 121})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 121})->frameRateSelectionStrategy, + scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren); + EXPECT_TRUE(getSnapshot({.id = 121})->changes.test(RequestedLayerState::Changes::FrameRate)); + + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 122})->frameRateSelectionStrategy, + scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren); + EXPECT_TRUE(getSnapshot({.id = 122})->changes.test(RequestedLayerState::Changes::FrameRate)); + + EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.vote.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 1221})->frameRateSelectionStrategy, + scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren); + EXPECT_TRUE(getSnapshot({.id = 1221})->changes.test(RequestedLayerState::Changes::FrameRate)); +} + TEST_F(LayerSnapshotTest, skipRoundCornersWhenProtected) { setRoundedCorners(1, 42.f); setRoundedCorners(2, 42.f); -- cgit v1.2.3-59-g8ed1b From 84541d153da755916306ec1181c623cb3c64cb09 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Fri, 29 Sep 2023 11:00:23 -0500 Subject: Synchronize access to Transaction::sApplyToken Speculative fix for flaky test AddWidgetTest#testDragIcon. Bug: 301158583 Test: presubmits Change-Id: Idc2e37d8b8e596e4a729621ecc5b7d5c8d7299a5 --- libs/gui/SurfaceComposerClient.cpp | 6 +++++- libs/gui/include/gui/SurfaceComposerClient.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 038764b800..8a57f925ec 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1227,7 +1227,7 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay flags |= ISurfaceComposer::eEarlyWakeupEnd; } - sp applyToken = mApplyToken ? mApplyToken : sApplyToken; + sp applyToken = mApplyToken ? mApplyToken : getDefaultApplyToken(); sp sf(ComposerService::getComposerService()); sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken, @@ -1249,11 +1249,15 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay sp SurfaceComposerClient::Transaction::sApplyToken = new BBinder(); +std::mutex SurfaceComposerClient::Transaction::sApplyTokenMutex; + sp SurfaceComposerClient::Transaction::getDefaultApplyToken() { + std::scoped_lock lock{sApplyTokenMutex}; return sApplyToken; } void SurfaceComposerClient::Transaction::setDefaultApplyToken(sp applyToken) { + std::scoped_lock lock{sApplyTokenMutex}; sApplyToken = applyToken; } diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 42e3c164ed..26b1fbd2ba 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -422,6 +422,7 @@ public: class Transaction : public Parcelable { private: static sp sApplyToken; + static std::mutex sApplyTokenMutex; void releaseBufferIfOverwriting(const layer_state_t& state); static void mergeFrameTimelineInfo(FrameTimelineInfo& t, const FrameTimelineInfo& other); -- cgit v1.2.3-59-g8ed1b From 67afbeaac2c284356f2b2aa61f48258bc0758911 Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Thu, 28 Sep 2023 15:35:07 -0700 Subject: Add smooth switch bool for setFrameRateCategory This allows the platform to have a different behavior depending on whether a device is MRR or dVRR. When the bool is `true`, MRR devices (those with DisplayModes that do not have vrr config) will not change frame rates if it would cause jank. The expected usage is to mark the bool true when an animation is running. Bug: 300491171 Test: atest libsurfaceflinger_unittest Change-Id: I5e87d276c11ecc806ede3e943f0a6498a7b910c4 --- libs/gui/LayerState.cpp | 7 +- libs/gui/SurfaceComposerClient.cpp | 3 +- libs/gui/include/gui/LayerState.h | 1 + libs/gui/include/gui/SurfaceComposerClient.h | 3 +- .../FrontEnd/RequestedLayerState.cpp | 1 + services/surfaceflinger/Layer.cpp | 6 +- services/surfaceflinger/Layer.h | 2 +- services/surfaceflinger/Scheduler/LayerHistory.cpp | 3 +- services/surfaceflinger/Scheduler/LayerInfo.cpp | 3 +- services/surfaceflinger/Scheduler/LayerInfo.h | 3 +- .../Scheduler/RefreshRateSelector.cpp | 30 +- .../surfaceflinger/Scheduler/RefreshRateSelector.h | 14 +- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- .../tests/unittests/RefreshRateSelectorTest.cpp | 470 +++++++++++++-------- 14 files changed, 366 insertions(+), 182 deletions(-) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 613721e103..fd8fc8d123 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -85,6 +85,7 @@ layer_state_t::layer_state_t() changeFrameRateStrategy(ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS), defaultFrameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), frameRateCategory(ANATIVEWINDOW_FRAME_RATE_CATEGORY_DEFAULT), + frameRateCategorySmoothSwitchOnly(false), frameRateSelectionStrategy(ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF), fixedTransformHint(ui::Transform::ROT_INVALID), autoRefresh(false), @@ -162,6 +163,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeByte, changeFrameRateStrategy); SAFE_PARCEL(output.writeByte, defaultFrameRateCompatibility); SAFE_PARCEL(output.writeByte, frameRateCategory); + SAFE_PARCEL(output.writeBool, frameRateCategorySmoothSwitchOnly); SAFE_PARCEL(output.writeByte, frameRateSelectionStrategy); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeBool, autoRefresh); @@ -296,6 +298,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readByte, &changeFrameRateStrategy); SAFE_PARCEL(input.readByte, &defaultFrameRateCompatibility); SAFE_PARCEL(input.readByte, &frameRateCategory); + SAFE_PARCEL(input.readBool, &frameRateCategorySmoothSwitchOnly); SAFE_PARCEL(input.readByte, &frameRateSelectionStrategy); SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); @@ -669,6 +672,7 @@ void layer_state_t::merge(const layer_state_t& other) { if (other.what & eFrameRateCategoryChanged) { what |= eFrameRateCategoryChanged; frameRateCategory = other.frameRateCategory; + frameRateCategorySmoothSwitchOnly = other.frameRateCategorySmoothSwitchOnly; } if (other.what & eFrameRateSelectionStrategyChanged) { what |= eFrameRateSelectionStrategyChanged; @@ -784,7 +788,8 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const { CHECK_DIFF(diff, eFrameRateSelectionPriority, other, frameRateSelectionPriority); CHECK_DIFF3(diff, eFrameRateChanged, other, frameRate, frameRateCompatibility, changeFrameRateStrategy); - CHECK_DIFF(diff, eFrameRateCategoryChanged, other, frameRateCategory); + CHECK_DIFF2(diff, eFrameRateCategoryChanged, other, frameRateCategory, + frameRateCategorySmoothSwitchOnly); CHECK_DIFF(diff, eFrameRateSelectionStrategyChanged, other, frameRateSelectionStrategy); CHECK_DIFF(diff, eFixedTransformHintChanged, other, fixedTransformHint); CHECK_DIFF(diff, eAutoRefreshChanged, other, autoRefresh); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 8a57f925ec..d9d99a414e 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2098,7 +2098,7 @@ SurfaceComposerClient::Transaction::setDefaultFrameRateCompatibility(const sp& sc, int8_t category) { + const sp& sc, int8_t category, bool smoothSwitchOnly) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; @@ -2106,6 +2106,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame } s->what |= layer_state_t::eFrameRateCategoryChanged; s->frameRateCategory = category; + s->frameRateCategorySmoothSwitchOnly = smoothSwitchOnly; return *this; } diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 4371007778..d3cde74963 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -361,6 +361,7 @@ struct layer_state_t { // Frame rate category to suggest what frame rate range a surface should run. int8_t frameRateCategory; + bool frameRateCategorySmoothSwitchOnly; // Strategy of the layer for frame rate selection. int8_t frameRateSelectionStrategy; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 26b1fbd2ba..bc63c412f7 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -686,7 +686,8 @@ public: Transaction& setDefaultFrameRateCompatibility(const sp& sc, int8_t compatibility); - Transaction& setFrameRateCategory(const sp& sc, int8_t category); + Transaction& setFrameRateCategory(const sp& sc, int8_t category, + bool smoothSwitchOnly); Transaction& setFrameRateSelectionStrategy(const sp& sc, int8_t strategy); diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index 168267bb50..087d7c89e4 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -124,6 +124,7 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) dimmingEnabled = true; defaultFrameRateCompatibility = static_cast(scheduler::FrameRateCompatibility::Default); frameRateCategory = static_cast(FrameRateCategory::Default); + frameRateCategorySmoothSwitchOnly = false; frameRateSelectionStrategy = static_cast(scheduler::LayerInfo::FrameRateSelectionStrategy::Self); dataspace = ui::Dataspace::V0_SRGB; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 2dc8758c3d..0c1c014640 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1334,13 +1334,15 @@ bool Layer::setFrameRate(FrameRate::FrameRateVote frameRateVote) { return true; } -bool Layer::setFrameRateCategory(FrameRateCategory category) { - if (mDrawingState.frameRate.category == category) { +bool Layer::setFrameRateCategory(FrameRateCategory category, bool smoothSwitchOnly) { + if (mDrawingState.frameRate.category == category && + mDrawingState.frameRate.categorySmoothSwitchOnly == smoothSwitchOnly) { return false; } mDrawingState.sequence++; mDrawingState.frameRate.category = category; + mDrawingState.frameRate.categorySmoothSwitchOnly = smoothSwitchOnly; mDrawingState.modified = true; updateTreeHasFrameRateVote(); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 0b66866158..1b9925539b 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -783,7 +783,7 @@ public: Rect getCroppedBufferSize(const Layer::State& s) const; bool setFrameRate(FrameRate::FrameRateVote); - bool setFrameRateCategory(FrameRateCategory); + bool setFrameRateCategory(FrameRateCategory, bool smoothSwitchOnly); bool setFrameRateSelectionStrategy(FrameRateSelectionStrategy); diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 4e5659ec5a..069d89bc42 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -194,7 +194,8 @@ auto LayerHistory::summarize(const RefreshRateSelector& selector, nsecs_t now) - to_string(vote.fps).c_str(), categoryString.c_str(), weight * 100); summary.push_back({info->getName(), info->getOwnerUid(), vote.type, vote.fps, - vote.seamlessness, vote.category, weight, layerFocused}); + vote.seamlessness, vote.category, vote.categorySmoothSwitchOnly, + weight, layerFocused}); if (CC_UNLIKELY(mTraceEnabled)) { trace(*info, vote.type, vote.fps.getIntValue()); diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index dd96930a06..36f2475d8e 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -309,7 +309,8 @@ LayerInfo::RefreshRateVotes LayerInfo::getRefreshRateVote(const RefreshRateSelec ALOGV("%s uses frame rate category: %d", mName.c_str(), static_cast(mLayerVote.category)); votes.push_back({LayerHistory::LayerVoteType::ExplicitCategory, Fps(), - Seamlessness::Default, mLayerVote.category}); + Seamlessness::Default, mLayerVote.category, + mLayerVote.categorySmoothSwitchOnly}); } if (mLayerVote.fps.isValid() || diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index d580b58f53..7d3cffabf7 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -71,8 +71,8 @@ public: LayerHistory::LayerVoteType type = LayerHistory::LayerVoteType::Heuristic; Fps fps; Seamlessness seamlessness = Seamlessness::Default; - // Category is in effect if fps is not specified. FrameRateCategory category = FrameRateCategory::Default; + bool categorySmoothSwitchOnly = false; // Returns true if the layer explicitly should contribute to frame rate scoring. bool isNoVote() const { return RefreshRateSelector::isNoVote(type); } @@ -111,6 +111,7 @@ public: } vote; FrameRateCategory category = FrameRateCategory::Default; + bool categorySmoothSwitchOnly = false; FrameRate() = default; diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index b06723ddab..1d23fb5f38 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -494,6 +494,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector 0 || @@ -578,10 +582,17 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector 0; + const DisplayModeId activeModeId = activeMode.getId(); + // Only if all layers want Min we should return Min if (noVoteLayers + minVoteLayers == layers.size()) { ALOGV("All layers Min"); - const auto ranking = rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Ascending); + const auto ranking = rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Ascending, + std::nullopt, [&](FrameRateMode mode) { + return !smoothSwitchOnly || + mode.modePtr->getId() == activeModeId; + }); ATRACE_FORMAT_INSTANT("%s (All layers Min)", to_string(ranking.front().frameRateMode.fps).c_str()); return {ranking, kNoSignals}; @@ -627,6 +638,14 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vectorgetId() != activeModeId) { + ALOGV("%s ignores %s because it's non-VRR and smooth switch only." + " Current mode = %s", + formatLayerInfo(layer, weight).c_str(), to_string(*modePtr).c_str(), + to_string(activeMode).c_str()); + continue; + } + // Layers with default seamlessness vote for the current mode group if // there are layers with seamlessness=SeamedAndSeamless and for the default // mode group otherwise. In second case, if the current mode group is different @@ -770,6 +789,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector anchorGroupOpt, RefreshRateOrder refreshRateOrder, - std::optional preferredDisplayModeOpt) const + std::optional preferredDisplayModeOpt, + const RankFrameRatesPredicate& predicate) const -> FrameRateRanking { using fps_approx_ops::operator<; const char* const whence = __func__; @@ -1044,7 +1067,8 @@ auto RefreshRateSelector::rankFrameRates(std::optional anchorGroupOpt, std::deque ranking; const auto rankFrameRate = [&](const FrameRateMode& frameRateMode) REQUIRES(mLock) { const auto& modePtr = frameRateMode.modePtr; - if (anchorGroupOpt && modePtr->getGroup() != anchorGroupOpt) { + if ((anchorGroupOpt && modePtr->getGroup() != anchorGroupOpt) || + !predicate(frameRateMode)) { return; } diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h index 5d32414ee5..545b939b3d 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h @@ -170,8 +170,11 @@ public: Fps desiredRefreshRate; // If a seamless mode switch is required. Seamlessness seamlessness = Seamlessness::Default; - // Layer frame rate category. Superseded by desiredRefreshRate. + // Layer frame rate category. FrameRateCategory frameRateCategory = FrameRateCategory::Default; + // Goes together with frame rate category vote. Allow refresh rate changes only + // if there would be no jank. + bool frameRateCategorySmoothSwitchOnly = false; // Layer's weight in the range of [0, 1]. The higher the weight the more impact this layer // would have on choosing the refresh rate. float weight = 0.0f; @@ -446,10 +449,15 @@ private: ftl_last = Descending }; - // Only uses the primary range, not the app request range. + typedef std::function RankFrameRatesPredicate; + + // Rank the frame rates. + // Only modes in the primary range for which `predicate` is `true` will be scored. + // Does not use the app requested range. FrameRateRanking rankFrameRates( std::optional anchorGroupOpt, RefreshRateOrder refreshRateOrder, - std::optional preferredDisplayModeOpt = std::nullopt) const + std::optional preferredDisplayModeOpt = std::nullopt, + const RankFrameRatesPredicate& predicate = [](FrameRateMode) { return true; }) const REQUIRES(mLock); const Policy* getCurrentPolicyLocked() const REQUIRES(mLock); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7e799bbe30..3d3c1690a1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5228,7 +5228,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime } if (what & layer_state_t::eFrameRateCategoryChanged) { const FrameRateCategory category = Layer::FrameRate::convertCategory(s.frameRateCategory); - if (layer->setFrameRateCategory(category)) { + if (layer->setFrameRateCategory(category, s.frameRateCategorySmoothSwitchOnly)) { flags |= eTraversalNeeded; } } diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index 0b671376f8..faa12a1032 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -117,9 +117,9 @@ struct TestableRefreshRateSelector : RefreshRateSelector { return std::make_pair(ranking, consideredSignals); } - ftl::NonNull getBestFrameRateMode( - const std::vector& layers = {}, GlobalSignals signals = {}) const { - return getRankedFrameRates(layers, signals).ranking.front().frameRateMode.modePtr; + FrameRateMode getBestFrameRateMode(const std::vector& layers = {}, + GlobalSignals signals = {}) const { + return getRankedFrameRates(layers, signals).ranking.front().frameRateMode; } ScoredFrameRate getBestScoredFrameRate(const std::vector& layers = {}, @@ -429,11 +429,11 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_noLayers) { // If there are no layers we select the default frame rate, which is the max of the primary // range. - EXPECT_EQ(kMode90, selector.getBestFrameRateMode()); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode().modePtr); EXPECT_EQ(SetPolicyResult::Changed, selector.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}})); - EXPECT_EQ(kMode60, selector.getBestFrameRateMode()); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode().modePtr); } { // We select max even when this will cause a non-seamless switch. @@ -442,7 +442,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_noLayers) { EXPECT_EQ(SetPolicyResult::Changed, selector.setDisplayManagerPolicy( {kModeId90, {0_Hz, 90_Hz}, kAllowGroupSwitching})); - EXPECT_EQ(kMode90_G1, selector.getBestFrameRateMode()); + EXPECT_EQ(kMode90_G1, selector.getBestFrameRateMode().modePtr); } } @@ -455,7 +455,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_exactDontChangeRefreshRateW EXPECT_EQ(SetPolicyResult::Changed, selector.setDisplayManagerPolicy({kModeId72, {0_Hz, 90_Hz}})); - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_60_90) { @@ -466,107 +466,107 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_60_90) { lr.vote = LayerVoteType::Min; lr.name = "Min"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; lr.name = "Max"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; lr.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Heuristic"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 45_Hz; lr.name = "45Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 30_Hz; lr.name = "30Hz Heuristic"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 24_Hz; lr.name = "24Hz Heuristic"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.name = ""; EXPECT_EQ(SetPolicyResult::Changed, selector.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}})); lr.vote = LayerVoteType::Min; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); EXPECT_EQ(SetPolicyResult::Changed, selector.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}})); lr.vote = LayerVoteType::Min; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); EXPECT_EQ(SetPolicyResult::Changed, selector.setDisplayManagerPolicy({kModeId60, {0_Hz, 120_Hz}})); lr.vote = LayerVoteType::Min; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_multipleThreshold_60_90) { @@ -577,32 +577,32 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_multipleThreshold_60_90) { lr.vote = LayerVoteType::Min; lr.name = "Min"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; lr.name = "Max"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; lr.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Heuristic"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 45_Hz; lr.name = "45Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 30_Hz; lr.name = "30Hz Heuristic"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 24_Hz; lr.name = "24Hz Heuristic"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_60_72_90) { @@ -612,26 +612,26 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_60_72_90) { auto& lr = layers[0]; lr.vote = LayerVoteType::Min; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_72_90_120) { @@ -645,19 +645,19 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_72_90_120) { lr1.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 48_Hz; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 48_Hz; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes) { @@ -673,7 +673,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -681,7 +681,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -689,7 +689,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "60Hz ExplicitDefault"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -697,7 +697,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -705,7 +705,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; @@ -713,7 +713,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::Heuristic; @@ -721,7 +721,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -729,7 +729,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; @@ -737,7 +737,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.name = "90Hz ExplicitExactOrMultiple"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, @@ -756,7 +756,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -764,7 +764,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -772,7 +772,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "60Hz ExplicitDefault"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -780,7 +780,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -788,7 +788,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; @@ -796,7 +796,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::Heuristic; @@ -804,7 +804,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -812,7 +812,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; @@ -820,14 +820,14 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.name = "90Hz ExplicitExactOrMultiple"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.name = "24Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -835,7 +835,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 120_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "120Hz ExplicitDefault"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -843,7 +843,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 120_Hz; lr2.vote = LayerVoteType::ExplicitExact; lr2.name = "120Hz ExplicitExact"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 10_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -851,7 +851,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 120_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "120Hz ExplicitExact"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 30_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -862,7 +862,7 @@ TEST_P(RefreshRateSelectorTest, lr3.vote = LayerVoteType::Heuristic; lr3.desiredRefreshRate = 120_Hz; lr3.name = "120Hz Heuristic"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60) { @@ -872,26 +872,26 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60) { auto& lr = layers[0]; lr.vote = LayerVoteType::Min; - EXPECT_EQ(kMode30, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode30, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(kMode30, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode30, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_72_90) { @@ -902,42 +902,42 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_72_90) { lr.vote = LayerVoteType::Min; lr.name = "Min"; - EXPECT_EQ(kMode30, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode30, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; lr.name = "Max"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; lr.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Heuristic"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); lr.desiredRefreshRate = 45_Hz; lr.name = "45Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); lr.desiredRefreshRate = 30_Hz; lr.name = "30Hz Heuristic"; - EXPECT_EQ(kMode30, selector.getBestFrameRateMode(layers)); - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode30, selector.getBestFrameRateMode(layers).modePtr); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); lr.desiredRefreshRate = 24_Hz; lr.name = "24Hz Heuristic"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); lr.desiredRefreshRate = 24_Hz; lr.vote = LayerVoteType::ExplicitExactOrMultiple; lr.name = "24Hz ExplicitExactOrMultiple"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_PriorityTest) { @@ -949,39 +949,39 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_PriorityTest) { lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::Max; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::Max; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::Max; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::Heuristic; lr1.desiredRefreshRate = 15_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::Heuristic; lr1.desiredRefreshRate = 30_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_24FpsVideo) { @@ -993,7 +993,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_24FpsVideo) { lr.vote = LayerVoteType::ExplicitExactOrMultiple; for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) { lr.desiredRefreshRate = Fps::fromValue(fps); - const auto mode = selector.getBestFrameRateMode(layers); + const auto mode = selector.getBestFrameRateMode(layers).modePtr; EXPECT_EQ(kMode60, mode) << lr.desiredRefreshRate << " chooses " << to_string(mode->getPeakFps()) << "(" << to_string(mode->getVsyncRate()) << ")"; @@ -1009,7 +1009,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_24FpsVideo_multipleThreshol lr.vote = LayerVoteType::ExplicitExactOrMultiple; for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) { lr.desiredRefreshRate = Fps::fromValue(fps); - const auto mode = selector.getBestFrameRateMode(layers); + const auto mode = selector.getBestFrameRateMode(layers).modePtr; EXPECT_EQ(kMode60, mode) << lr.desiredRefreshRate << " chooses " << to_string(mode->getPeakFps()) << "(" << to_string(mode->getVsyncRate()) << ")"; @@ -1027,19 +1027,19 @@ TEST_P(RefreshRateSelectorTest, twoModes_getBestFrameRateMode_Explicit) { lr1.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 90_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::ExplicitDefault; lr1.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::Heuristic; lr1.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_75HzContent) { @@ -1051,7 +1051,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_75HzContent) { lr.vote = LayerVoteType::ExplicitExactOrMultiple; for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) { lr.desiredRefreshRate = Fps::fromValue(fps); - const auto mode = selector.getBestFrameRateMode(layers, {}); + const auto mode = selector.getBestFrameRateMode(layers, {}).modePtr; EXPECT_EQ(kMode90, mode) << lr.desiredRefreshRate << " chooses " << to_string(mode->getPeakFps()) << "(" << to_string(mode->getVsyncRate()) << ")"; @@ -1071,7 +1071,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_Multiples) { lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 90_Hz; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60_Hz; @@ -1079,14 +1079,14 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_Multiples) { lr2.vote = LayerVoteType::ExplicitDefault; lr2.desiredRefreshRate = 90_Hz; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 30_Hz; @@ -1094,14 +1094,14 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_Multiples) { lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 90_Hz; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 30_Hz; lr1.name = "30Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, scrollWhileWatching60fps_60_90) { @@ -1116,28 +1116,28 @@ TEST_P(RefreshRateSelectorTest, scrollWhileWatching60fps_60_90) { lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::NoVote; lr2.name = "NoVote"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::NoVote; lr2.name = "NoVote"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); // The other layer starts to provide buffers lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -1146,7 +1146,7 @@ TEST_P(RefreshRateSelectorTest, scrollWhileWatching60fps_60_90) { lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 90_Hz; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getMaxRefreshRatesByPolicy) { @@ -1464,7 +1464,8 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_30_60 layers.push_back(layer); } - EXPECT_EQ(testCase.expectedFrameRate, selector.getBestFrameRateMode(layers)->getPeakFps()) + EXPECT_EQ(testCase.expectedFrameRate, + selector.getBestFrameRateMode(layers).modePtr->getPeakFps()) << "Did not get expected frame rate for frameRate=" << to_string(testCase.desiredFrameRate) << " category=" << ftl::enum_string(testCase.frameRateCategory); @@ -1528,13 +1529,147 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_60_12 layers.push_back(layer); } - EXPECT_EQ(testCase.expectedFrameRate, selector.getBestFrameRateMode(layers)->getPeakFps()) + EXPECT_EQ(testCase.expectedFrameRate, + selector.getBestFrameRateMode(layers).modePtr->getPeakFps()) << "Did not get expected frame rate for frameRate=" << to_string(testCase.desiredFrameRate) << " category=" << ftl::enum_string(testCase.frameRateCategory); } } +TEST_P(RefreshRateSelectorTest, + getBestFrameRateMode_withFrameRateCategory_smoothSwitchOnly_60_120_nonVrr) { + if (GetParam() != Config::FrameRateOverride::Enabled) { + return; + } + + // VRR compatibility is determined by the presence of a vrr config in the DisplayMode. + auto selector = createSelector(makeModes(kMode60, kMode120), kModeId120); + + struct Case { + // Params + FrameRateCategory frameRateCategory = FrameRateCategory::Default; + bool smoothSwitchOnly = false; + + // Expected result + Fps expectedFrameRate = 0_Hz; + DisplayModeId expectedModeId = kModeId60; + }; + + const std::initializer_list testCases = { + // These layers may switch modes because smoothSwitchOnly=false. + {FrameRateCategory::Default, false, 120_Hz, kModeId120}, + // TODO(b/266481656): Once this bug is fixed, NoPreference should be a lower frame rate. + {FrameRateCategory::NoPreference, false, 60_Hz, kModeId60}, + {FrameRateCategory::Low, false, 30_Hz, kModeId60}, + {FrameRateCategory::Normal, false, 60_Hz, kModeId60}, + {FrameRateCategory::High, false, 120_Hz, kModeId120}, + + // These layers cannot change mode due to smoothSwitchOnly, and will definitely use + // active mode (120Hz). + {FrameRateCategory::NoPreference, true, 120_Hz, kModeId120}, + {FrameRateCategory::Low, true, 40_Hz, kModeId120}, + {FrameRateCategory::Normal, true, 40_Hz, kModeId120}, + {FrameRateCategory::High, true, 120_Hz, kModeId120}, + }; + + for (auto testCase : testCases) { + std::vector layers; + ALOGI("**** %s: Testing frameRateCategory=%s (smooth=%d)", __func__, + ftl::enum_string(testCase.frameRateCategory).c_str(), testCase.smoothSwitchOnly); + + if (testCase.frameRateCategory != FrameRateCategory::Default) { + std::stringstream ss; + ss << "ExplicitCategory (" << ftl::enum_string(testCase.frameRateCategory) + << " smooth:" << testCase.smoothSwitchOnly << ")"; + LayerRequirement layer = {.name = ss.str(), + .vote = LayerVoteType::ExplicitCategory, + .frameRateCategory = testCase.frameRateCategory, + .frameRateCategorySmoothSwitchOnly = + testCase.smoothSwitchOnly, + .weight = 1.f}; + layers.push_back(layer); + } + + auto actualFrameRateMode = selector.getBestFrameRateMode(layers); + EXPECT_EQ(testCase.expectedFrameRate, actualFrameRateMode.fps) + << "Did not get expected frame rate for category=" + << ftl::enum_string(testCase.frameRateCategory) + << " (smooth=" << testCase.smoothSwitchOnly << ")"; + + EXPECT_EQ(testCase.expectedModeId, actualFrameRateMode.modePtr->getId()) + << "Did not get expected mode for category=" + << ftl::enum_string(testCase.frameRateCategory) + << " (smooth=" << testCase.smoothSwitchOnly << ")"; + } +} + +TEST_P(RefreshRateSelectorTest, + getBestFrameRateMode_withFrameRateCategory_smoothSwitchOnly_60_120_vrr) { + if (GetParam() != Config::FrameRateOverride::Enabled) { + return; + } + + // VRR compatibility is determined by the presence of a vrr config in the DisplayMode. + auto selector = createSelector(kVrrModes_60_120, kModeId120); + + struct Case { + // Params + FrameRateCategory frameRateCategory = FrameRateCategory::Default; + bool smoothSwitchOnly = false; + + // Expected result + Fps expectedFrameRate = 0_Hz; + }; + + // Note that `smoothSwitchOnly` should not have an effect. + const std::initializer_list testCases = { + {FrameRateCategory::Default, false, 240_Hz}, + // TODO(b/266481656): Once this bug is fixed, NoPreference should be a lower frame rate. + {FrameRateCategory::NoPreference, false, 240_Hz}, + {FrameRateCategory::Low, false, 30_Hz}, + {FrameRateCategory::Normal, false, 60_Hz}, + {FrameRateCategory::High, false, 120_Hz}, + {FrameRateCategory::Default, true, 240_Hz}, + // TODO(b/266481656): Once this bug is fixed, NoPreference should be a lower frame rate. + {FrameRateCategory::NoPreference, true, 240_Hz}, + {FrameRateCategory::Low, true, 30_Hz}, + {FrameRateCategory::Normal, true, 60_Hz}, + {FrameRateCategory::High, true, 120_Hz}, + }; + + for (auto testCase : testCases) { + std::vector layers; + ALOGI("**** %s: Testing frameRateCategory=%s (smooth=%d)", __func__, + ftl::enum_string(testCase.frameRateCategory).c_str(), testCase.smoothSwitchOnly); + + if (testCase.frameRateCategory != FrameRateCategory::Default) { + std::stringstream ss; + ss << "ExplicitCategory (" << ftl::enum_string(testCase.frameRateCategory) + << " smooth:" << testCase.smoothSwitchOnly << ")"; + LayerRequirement layer = {.name = ss.str(), + .vote = LayerVoteType::ExplicitCategory, + .frameRateCategory = testCase.frameRateCategory, + .frameRateCategorySmoothSwitchOnly = + testCase.smoothSwitchOnly, + .weight = 1.f}; + layers.push_back(layer); + } + + auto actualFrameRateMode = selector.getBestFrameRateMode(layers); + EXPECT_EQ(testCase.expectedFrameRate, actualFrameRateMode.fps) + << "Did not get expected frame rate for category=" + << ftl::enum_string(testCase.frameRateCategory) + << " (smooth=" << testCase.smoothSwitchOnly << ")"; + + // Expect all cases to be able to stay at the mode with TE 240 due to VRR compatibility. + EXPECT_EQ(kVrrMode120TE240->getId(), actualFrameRateMode.modePtr->getId()) + << "Did not get expected mode for category=" + << ftl::enum_string(testCase.frameRateCategory) + << " (smooth=" << testCase.smoothSwitchOnly << ")"; + } +} + TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_ExplicitDefault) { auto selector = createSelector(kModes_60_90_72_120, kModeId60); @@ -1568,7 +1703,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_ExplicitDefault) { ss << "ExplicitDefault " << desired; lr.name = ss.str(); - const auto bestMode = selector.getBestFrameRateMode(layers); + const auto bestMode = selector.getBestFrameRateMode(layers).modePtr; EXPECT_EQ(expected, bestMode->getPeakFps()) << "expected " << expected << " for " << desired << " but got " << bestMode->getPeakFps() << "(" << bestMode->getVsyncRate() << ")"; @@ -1589,7 +1724,7 @@ TEST_P(RefreshRateSelectorTest, lr.vote = LayerVoteType::ExplicitExactOrMultiple; lr.desiredRefreshRate = 23.976_Hz; lr.name = "ExplicitExactOrMultiple 23.976 Hz"; - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers).modePtr->getId()); } // Test that 24 will choose 23.976 if 24 is not supported @@ -1600,7 +1735,7 @@ TEST_P(RefreshRateSelectorTest, lr.desiredRefreshRate = 24_Hz; lr.name = "ExplicitExactOrMultiple 24 Hz"; - EXPECT_EQ(kModeId24Frac, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId24Frac, selector.getBestFrameRateMode(layers).modePtr->getId()); } // Test that 29.97 will prefer 59.94 over 60 and 30 @@ -1611,7 +1746,7 @@ TEST_P(RefreshRateSelectorTest, lr.desiredRefreshRate = 29.97_Hz; lr.name = "ExplicitExactOrMultiple 29.97 Hz"; - EXPECT_EQ(kModeId60Frac, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60Frac, selector.getBestFrameRateMode(layers).modePtr->getId()); } // Test that 29.97 will choose 60 if 59.94 is not supported @@ -1620,7 +1755,7 @@ TEST_P(RefreshRateSelectorTest, lr.desiredRefreshRate = 29.97_Hz; lr.name = "ExplicitExactOrMultiple 29.97 Hz"; - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers).modePtr->getId()); } // Test that 59.94 will choose 60 if 59.94 is not supported @@ -1629,7 +1764,7 @@ TEST_P(RefreshRateSelectorTest, lr.desiredRefreshRate = 59.94_Hz; lr.name = "ExplicitExactOrMultiple 59.94 Hz"; - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers).modePtr->getId()); } } @@ -1648,7 +1783,8 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_ExplicitExact_WithFractiona ss << "ExplicitExact " << desired; lr.name = ss.str(); - EXPECT_EQ(lr.desiredRefreshRate, selector.getBestFrameRateMode(layers)->getPeakFps()); + EXPECT_EQ(lr.desiredRefreshRate, + selector.getBestFrameRateMode(layers).modePtr->getPeakFps()); } } } @@ -1694,7 +1830,7 @@ TEST_P(RefreshRateSelectorTest, lr.desiredRefreshRate = 90_Hz; lr.name = "90Hz ExplicitDefault"; lr.focused = true; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.idle = true})); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.idle = true}).modePtr); } TEST_P(RefreshRateSelectorTest, testDisplayModeOrdering) { @@ -1905,46 +2041,46 @@ TEST_P(RefreshRateSelectorTest, lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz ExplicitExactOrMultiple"; lr.focused = false; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.focused = true; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::ExplicitDefault; lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz ExplicitDefault"; lr.focused = false; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.focused = true; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Heuristic; lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Heuristic"; lr.focused = false; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.focused = true; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Max"; lr.focused = false; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.focused = true; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Min; lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Min"; lr.focused = false; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.focused = true; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, groupSwitchingNotAllowed) { @@ -1960,7 +2096,7 @@ TEST_P(RefreshRateSelectorTest, groupSwitchingNotAllowed) { layer.name = "90Hz ExplicitDefault"; layer.focused = true; - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, groupSwitchingWithOneLayer) { @@ -1978,7 +2114,7 @@ TEST_P(RefreshRateSelectorTest, groupSwitchingWithOneLayer) { layer.seamlessness = Seamlessness::SeamedAndSeamless; layer.name = "90Hz ExplicitDefault"; layer.focused = true; - EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, groupSwitchingWithOneLayerOnlySeamless) { @@ -1997,7 +2133,7 @@ TEST_P(RefreshRateSelectorTest, groupSwitchingWithOneLayerOnlySeamless) { layer.seamlessness = Seamlessness::OnlySeamless; layer.name = "90Hz ExplicitDefault"; layer.focused = true; - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, groupSwitchingWithOneLayerOnlySeamlessDefaultFps) { @@ -2018,7 +2154,7 @@ TEST_P(RefreshRateSelectorTest, groupSwitchingWithOneLayerOnlySeamlessDefaultFps layer.seamlessness = Seamlessness::OnlySeamless; layer.name = "60Hz ExplicitDefault"; layer.focused = true; - EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, groupSwitchingWithOneLayerDefaultSeamlessness) { @@ -2042,7 +2178,7 @@ TEST_P(RefreshRateSelectorTest, groupSwitchingWithOneLayerDefaultSeamlessness) { layer.name = "60Hz ExplicitDefault"; layer.focused = true; - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, groupSwitchingWithTwoLayersOnlySeamlessAndSeamed) { @@ -2071,7 +2207,7 @@ TEST_P(RefreshRateSelectorTest, groupSwitchingWithTwoLayersOnlySeamlessAndSeamed layers[1].name = "90Hz ExplicitDefault"; layers[1].focused = false; - EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, groupSwitchingWithTwoLayersDefaultFocusedAndSeamed) { @@ -2104,7 +2240,7 @@ TEST_P(RefreshRateSelectorTest, groupSwitchingWithTwoLayersDefaultFocusedAndSeam layers[1].vote = LayerVoteType::ExplicitDefault; layers[1].name = "90Hz ExplicitDefault"; - EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, groupSwitchingWithTwoLayersDefaultNotFocusedAndSeamed) { @@ -2134,7 +2270,7 @@ TEST_P(RefreshRateSelectorTest, groupSwitchingWithTwoLayersDefaultNotFocusedAndS layers[1].vote = LayerVoteType::ExplicitDefault; layers[1].name = "90Hz ExplicitDefault"; - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, nonSeamlessVotePrefersSeamlessSwitches) { @@ -2154,10 +2290,10 @@ TEST_P(RefreshRateSelectorTest, nonSeamlessVotePrefersSeamlessSwitches) { layer.name = "60Hz ExplicitExactOrMultiple"; layer.focused = true; - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers).modePtr->getId()); selector.setActiveMode(kModeId120, 120_Hz); - EXPECT_EQ(kModeId120, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId120, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, nonSeamlessExactAndSeamlessMultipleLayers) { @@ -2182,14 +2318,14 @@ TEST_P(RefreshRateSelectorTest, nonSeamlessExactAndSeamlessMultipleLayers) { .weight = 1.f, .focused = true}}; - EXPECT_EQ(kModeId50, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId50, selector.getBestFrameRateMode(layers).modePtr->getId()); auto& seamedLayer = layers[0]; seamedLayer.desiredRefreshRate = 30_Hz; seamedLayer.name = "30Hz ExplicitDefault"; selector.setActiveMode(kModeId30, 30_Hz); - EXPECT_EQ(kModeId25, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId25, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, minLayersDontTrigerSeamedSwitch) { @@ -2204,7 +2340,7 @@ TEST_P(RefreshRateSelectorTest, minLayersDontTrigerSeamedSwitch) { std::vector layers = { {.name = "Min", .vote = LayerVoteType::Min, .weight = 1.f, .focused = true}}; - EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, primaryVsAppRequestPolicy) { @@ -2225,7 +2361,7 @@ TEST_P(RefreshRateSelectorTest, primaryVsAppRequestPolicy) { layers[0].vote = voteType; layers[0].desiredRefreshRate = fps; layers[0].focused = args.focused; - return selector.getBestFrameRateMode(layers, {.touch = args.touch})->getId(); + return selector.getBestFrameRateMode(layers, {.touch = args.touch}).modePtr->getId(); }; constexpr FpsRange k30_60 = {30_Hz, 60_Hz}; @@ -2234,7 +2370,7 @@ TEST_P(RefreshRateSelectorTest, primaryVsAppRequestPolicy) { EXPECT_EQ(SetPolicyResult::Changed, selector.setDisplayManagerPolicy({kModeId60, {k30_60, k30_60}, {k30_90, k30_90}})); - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode()->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode().modePtr->getId()); EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::NoVote, 90_Hz)); EXPECT_EQ(kModeId30, getFrameRate(LayerVoteType::Min, 90_Hz)); EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Max, 90_Hz)); @@ -2302,7 +2438,8 @@ TEST_P(RefreshRateSelectorTest, idle) { } // With no layers, idle should still be lower priority than touch boost. - EXPECT_EQ(kModeId90, selector.getBestFrameRateMode({}, {.touch = true, .idle = true})->getId()); + EXPECT_EQ(kModeId90, + selector.getBestFrameRateMode({}, {.touch = true, .idle = true}).modePtr->getId()); // Idle should be higher precedence than other layer frame rate considerations. selector.setActiveMode(kModeId90, 90_Hz); @@ -2319,7 +2456,7 @@ TEST_P(RefreshRateSelectorTest, idle) { } // Idle should be applied rather than the active mode when there are no layers. - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode({}, {.idle = true})->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode({}, {.idle = true}).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, findClosestKnownFrameRate) { @@ -2368,7 +2505,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_KnownFrameRate) { for (const auto& [fps, mode] : knownFrameRatesExpectations) { layer.desiredRefreshRate = fps; - EXPECT_EQ(mode, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(mode, selector.getBestFrameRateMode(layers).modePtr); } } @@ -2471,17 +2608,17 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_ExplicitExactTouchBoost) { explicitExactLayer.name = "ExplicitExact"; explicitExactLayer.desiredRefreshRate = 30_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); if (GetParam() == Config::FrameRateOverride::Disabled) { - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); } else { - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); } explicitExactOrMultipleLayer.vote = LayerVoteType::NoVote; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_FractionalRefreshRates_ExactAndDefault) { @@ -2499,7 +2636,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_FractionalRefreshRates_Exac explicitDefaultLayer.name = "ExplicitDefault"; explicitDefaultLayer.desiredRefreshRate = 59.94_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); } // b/190578904 @@ -2526,7 +2663,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withCloseRefreshRates) { layers[0].desiredRefreshRate = fps; layers[0].vote = vote; EXPECT_EQ(fps.getIntValue(), - selector.getBestFrameRateMode(layers)->getPeakFps().getIntValue()) + selector.getBestFrameRateMode(layers).modePtr->getPeakFps().getIntValue()) << "Failed for " << ftl::enum_string(vote); }; @@ -2565,7 +2702,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_conflictingVotes) { }, }; - EXPECT_EQ(53_Hz, selector.getBestFrameRateMode(layers, globalSignals)->getPeakFps()); + EXPECT_EQ(53_Hz, selector.getBestFrameRateMode(layers, globalSignals).modePtr->getPeakFps()); } TEST_P(RefreshRateSelectorTest, modeComparison) { @@ -3176,7 +3313,8 @@ TEST_P(RefreshRateSelectorTest, idleWhenLowestRefreshRateIsNotDivisor) { selector.setDisplayManagerPolicy({kModeId60, {0_Hz, 90_Hz}})); // With no layers, idle should still be lower priority than touch boost. - EXPECT_EQ(kModeId90, selector.getBestFrameRateMode({}, {.touch = true, .idle = true})->getId()); + EXPECT_EQ(kModeId90, + selector.getBestFrameRateMode({}, {.touch = true, .idle = true}).modePtr->getId()); // Idle should be higher precedence than other layer frame rate considerations. selector.setActiveMode(kModeId90, 90_Hz); @@ -3192,7 +3330,7 @@ TEST_P(RefreshRateSelectorTest, idleWhenLowestRefreshRateIsNotDivisor) { } // Idle should be applied rather than the active mode when there are no layers. - EXPECT_EQ(kModeId35, selector.getBestFrameRateMode({}, {.idle = true})->getId()); + EXPECT_EQ(kModeId35, selector.getBestFrameRateMode({}, {.idle = true}).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, policyCanBeInfinity) { -- cgit v1.2.3-59-g8ed1b From d122a1cb046cc6ebf0aa34b91c9dca2e9741e6a8 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Sat, 30 Sep 2023 01:36:33 +0000 Subject: Add vsync rate to DisplayMode Bug: 301462354 Test: builds Test: dumpsys display Change-Id: I68bf4a12b8f730af529ea6ce1047cd294180499a --- libs/gui/SurfaceComposerClient.cpp | 1 + libs/gui/aidl/android/gui/DisplayMode.aidl | 2 ++ libs/ui/include/ui/DisplayMode.h | 4 +++- services/surfaceflinger/SurfaceFlinger.cpp | 2 ++ 4 files changed, 8 insertions(+), 1 deletion(-) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 8a57f925ec..f0604b9bfc 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2604,6 +2604,7 @@ void SurfaceComposerClient::getDynamicDisplayInfoInternal(gui::DynamicDisplayInf outMode.xDpi = mode.xDpi; outMode.yDpi = mode.yDpi; outMode.refreshRate = mode.refreshRate; + outMode.vsyncRate = mode.vsyncRate; outMode.appVsyncOffset = mode.appVsyncOffset; outMode.sfVsyncOffset = mode.sfVsyncOffset; outMode.presentationDeadline = mode.presentationDeadline; diff --git a/libs/gui/aidl/android/gui/DisplayMode.aidl b/libs/gui/aidl/android/gui/DisplayMode.aidl index ce30426cb5..b057653200 100644 --- a/libs/gui/aidl/android/gui/DisplayMode.aidl +++ b/libs/gui/aidl/android/gui/DisplayMode.aidl @@ -29,7 +29,9 @@ parcelable DisplayMode { float yDpi = 0.0f; int[] supportedHdrTypes; + // Some modes have peak refresh rate lower than the panel vsync rate. float refreshRate = 0.0f; + float vsyncRate = 0.0f; long appVsyncOffset = 0; long sfVsyncOffset = 0; long presentationDeadline = 0; diff --git a/libs/ui/include/ui/DisplayMode.h b/libs/ui/include/ui/DisplayMode.h index 65a8769c98..a469c78070 100644 --- a/libs/ui/include/ui/DisplayMode.h +++ b/libs/ui/include/ui/DisplayMode.h @@ -37,7 +37,9 @@ struct DisplayMode { float yDpi = 0; std::vector supportedHdrTypes; - float refreshRate = 0; + // Some modes have peak refresh rate lower than the panel vsync rate. + float refreshRate = 0.f; + float vsyncRate = 0.f; nsecs_t appVsyncOffset = 0; nsecs_t sfVsyncOffset = 0; nsecs_t presentationDeadline = 0; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7e799bbe30..e08690a2bb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1047,6 +1047,7 @@ void SurfaceFlinger::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo*& info const auto peakFps = mode->getPeakFps(); outMode.refreshRate = peakFps.getValue(); + outMode.vsyncRate = mode->getVsyncRate().getValue(); const auto vsyncConfigSet = mVsyncConfiguration->getConfigsForRefreshRate(Fps::fromValue(outMode.refreshRate)); @@ -9189,6 +9190,7 @@ void SurfaceComposerAIDL::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo& outMode.xDpi = mode.xDpi; outMode.yDpi = mode.yDpi; outMode.refreshRate = mode.refreshRate; + outMode.vsyncRate = mode.vsyncRate; outMode.appVsyncOffset = mode.appVsyncOffset; outMode.sfVsyncOffset = mode.sfVsyncOffset; outMode.presentationDeadline = mode.presentationDeadline; -- cgit v1.2.3-59-g8ed1b From f3621106fc277a0b16609927e81a47aca87c22c6 Mon Sep 17 00:00:00 2001 From: Tony Huang Date: Mon, 4 Sep 2023 17:14:22 +0800 Subject: VRR: Use appId to replace uid mapping Uid is combination of user id and app id. Because the allowlist is recored by pkg for each users. We could ignore the user id part and it also could solve the issue we didn't update the mapping when user added case. Bug: 298722189 Test: atest SmallAreaDetectionAllowMappingsTest Test: atest SmallAreaDetectionControllerTest Test: Add new user and open Youtube short to check refresh rate Change-Id: Ic80be38ebc19938bc061bf6121c68efc4ff9ac4c --- libs/gui/SurfaceComposerClient.cpp | 8 ++--- libs/gui/aidl/android/gui/ISurfaceComposer.aidl | 8 ++--- libs/gui/include/gui/SurfaceComposerClient.h | 10 +++--- libs/gui/tests/Surface_test.cpp | 4 +-- services/surfaceflinger/Layer.cpp | 3 +- services/surfaceflinger/Layer.h | 8 +++++ services/surfaceflinger/Scheduler/Scheduler.cpp | 15 ++++----- services/surfaceflinger/Scheduler/Scheduler.h | 6 ++-- .../Scheduler/SmallAreaDetectionAllowMappings.cpp | 12 ++++---- .../Scheduler/SmallAreaDetectionAllowMappings.h | 10 +++--- services/surfaceflinger/SurfaceFlinger.cpp | 22 ++++++------- services/surfaceflinger/SurfaceFlinger.h | 8 ++--- .../SmallAreaDetectionAllowMappingsTest.cpp | 36 ++++++++++------------ 13 files changed, 78 insertions(+), 72 deletions(-) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 4db960e7fa..d23b9e66a9 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2768,16 +2768,16 @@ status_t SurfaceComposerClient::setOverrideFrameRate(uid_t uid, float frameRate) return statusTFromBinderStatus(status); } -status_t SurfaceComposerClient::updateSmallAreaDetection(std::vector& uids, +status_t SurfaceComposerClient::updateSmallAreaDetection(std::vector& appIds, std::vector& thresholds) { binder::Status status = - ComposerServiceAIDL::getComposerService()->updateSmallAreaDetection(uids, thresholds); + ComposerServiceAIDL::getComposerService()->updateSmallAreaDetection(appIds, thresholds); return statusTFromBinderStatus(status); } -status_t SurfaceComposerClient::setSmallAreaDetectionThreshold(uid_t uid, float threshold) { +status_t SurfaceComposerClient::setSmallAreaDetectionThreshold(int32_t appId, float threshold) { binder::Status status = - ComposerServiceAIDL::getComposerService()->setSmallAreaDetectionThreshold(uid, + ComposerServiceAIDL::getComposerService()->setSmallAreaDetectionThreshold(appId, threshold); return statusTFromBinderStatus(status); } diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index 1c604a1f8b..2c8b4b83ca 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -479,14 +479,14 @@ interface ISurfaceComposer { */ void setOverrideFrameRate(int uid, float frameRate); - oneway void updateSmallAreaDetection(in int[] uids, in float[] thresholds); + oneway void updateSmallAreaDetection(in int[] appIds, in float[] thresholds); /** - * Set the small area detection threshold for a specified uid by SmallAreaDetectionController. - * Passing the threshold and uid to SurfaceFlinger to update the uid-threshold mapping + * Set the small area detection threshold for a specified appId by SmallAreaDetectionController. + * Passing the threshold and appId to SurfaceFlinger to update the appId-threshold mapping * in the scheduler. */ - oneway void setSmallAreaDetectionThreshold(int uid, float threshold); + oneway void setSmallAreaDetectionThreshold(int appId, float threshold); /** * Enables or disables the frame rate overlay in the top left corner. diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 6fef5d2378..cb48807207 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -203,15 +203,15 @@ public: // by GameManager. static status_t setOverrideFrameRate(uid_t uid, float frameRate); - // Update the small area detection whole uid-threshold mappings by same size uid and threshold - // vector. + // Update the small area detection whole appId-threshold mappings by same size appId and + // threshold vector. // Ref:setSmallAreaDetectionThreshold. - static status_t updateSmallAreaDetection(std::vector& uids, + static status_t updateSmallAreaDetection(std::vector& appIds, std::vector& thresholds); - // Sets the small area detection threshold to particular apps (uid). Passing value 0 means + // Sets the small area detection threshold to particular apps (appId). Passing value 0 means // to disable small area detection to the app. - static status_t setSmallAreaDetectionThreshold(uid_t uid, float threshold); + static status_t setSmallAreaDetectionThreshold(int32_t appId, float threshold); // 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 daed764cd6..edd95bad6d 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -999,12 +999,12 @@ public: binder::Status scheduleCommit() override { return binder::Status::ok(); } - binder::Status updateSmallAreaDetection(const std::vector& /*uids*/, + binder::Status updateSmallAreaDetection(const std::vector& /*appIds*/, const std::vector& /*thresholds*/) { return binder::Status::ok(); } - binder::Status setSmallAreaDetectionThreshold(int32_t /*uid*/, float /*threshold*/) { + binder::Status setSmallAreaDetectionThreshold(int32_t /*appId*/, float /*threshold*/) { return binder::Status::ok(); } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 9a5173ba9b..6b5613849a 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -205,6 +205,7 @@ Layer::Layer(const surfaceflinger::LayerCreationArgs& args) mOwnerUid = args.ownerUid; mOwnerPid = args.ownerPid; + mOwnerAppId = mOwnerUid % PER_USER_RANGE; mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied); mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow; @@ -4388,7 +4389,7 @@ void Layer::setIsSmallDirty() { // If the damage region is a small dirty, this could give the hint for the layer history that // it could suppress the heuristic rate when calculating. - mSmallDirty = mFlinger->mScheduler->isSmallDirtyArea(mOwnerUid, + mSmallDirty = mFlinger->mScheduler->isSmallDirtyArea(mOwnerAppId, bounds.getWidth() * bounds.getHeight()); } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index dc4ceb0bfa..e67a290d50 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -831,6 +831,8 @@ public: pid_t getOwnerPid() { return mOwnerPid; } + int32_t getOwnerAppId() { return mOwnerAppId; } + // This layer is not a clone, but it's the parent to the cloned hierarchy. The // variable mClonedChild represents the top layer that will be cloned so this // layer will be the parent of mClonedChild. @@ -1056,6 +1058,8 @@ protected: // If created from a system process, the value can be passed in. pid_t mOwnerPid; + int32_t mOwnerAppId; + // Keeps track of the time SF latched the last buffer from this layer. // Used in buffer stuffing analysis in FrameTimeline. nsecs_t mLastLatchTime = 0; @@ -1065,6 +1069,10 @@ protected: sp mLastClientCompositionFence; bool mClearClientCompositionFenceOnLayerDisplayed = false; private: + // Range of uids allocated for a user. + // This value is taken from android.os.UserHandle#PER_USER_RANGE. + static constexpr int32_t PER_USER_RANGE = 100000; + friend class SlotGenerationTest; friend class TransactionFrameTracerTest; friend class TransactionSurfaceFrameTest; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 27c96f7d4f..09ce9a68e8 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -1180,18 +1180,19 @@ void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverrid } void Scheduler::updateSmallAreaDetection( - std::vector>& uidThresholdMappings) { + std::vector>& uidThresholdMappings) { mSmallAreaDetectionAllowMappings.update(uidThresholdMappings); } -void Scheduler::setSmallAreaDetectionThreshold(uid_t uid, float threshold) { - mSmallAreaDetectionAllowMappings.setThesholdForUid(uid, threshold); +void Scheduler::setSmallAreaDetectionThreshold(int32_t appId, float threshold) { + mSmallAreaDetectionAllowMappings.setThesholdForAppId(appId, threshold); } -bool Scheduler::isSmallDirtyArea(uid_t uid, uint32_t dirtyArea) { - std::optional oThreshold = mSmallAreaDetectionAllowMappings.getThresholdForUid(uid); - if (oThreshold) return mLayerHistory.isSmallDirtyArea(dirtyArea, oThreshold.value()); - +bool Scheduler::isSmallDirtyArea(int32_t appId, uint32_t dirtyArea) { + std::optional oThreshold = mSmallAreaDetectionAllowMappings.getThresholdForAppId(appId); + if (oThreshold) { + return mLayerHistory.isSmallDirtyArea(dirtyArea, oThreshold.value()); + } return false; } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index d65df2a65d..23a21e8170 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -292,12 +292,12 @@ public: void setGameModeRefreshRateForUid(FrameRateOverride); - void updateSmallAreaDetection(std::vector>& uidThresholdMappings); + void updateSmallAreaDetection(std::vector>& uidThresholdMappings); - void setSmallAreaDetectionThreshold(uid_t uid, float threshold); + void setSmallAreaDetectionThreshold(int32_t appId, float threshold); // Returns true if the dirty area is less than threshold. - bool isSmallDirtyArea(uid_t uid, uint32_t dirtyArea); + bool isSmallDirtyArea(int32_t appId, uint32_t dirtyArea); // Retrieves the overridden refresh rate for a given uid. std::optional getFrameRateOverride(uid_t) const EXCLUDES(mDisplayLock); diff --git a/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp index 95cd5d199a..38c6da48f6 100644 --- a/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp +++ b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp @@ -19,26 +19,26 @@ namespace android::scheduler { void SmallAreaDetectionAllowMappings::update( - std::vector>& uidThresholdMappings) { + std::vector>& appIdThresholdMappings) { std::lock_guard lock(mLock); mMap.clear(); - for (std::pair row : uidThresholdMappings) { + for (std::pair row : appIdThresholdMappings) { if (!isValidThreshold(row.second)) continue; mMap.emplace(row.first, row.second); } } -void SmallAreaDetectionAllowMappings::setThesholdForUid(uid_t uid, float threshold) { +void SmallAreaDetectionAllowMappings::setThesholdForAppId(int32_t appId, float threshold) { if (!isValidThreshold(threshold)) return; std::lock_guard lock(mLock); - mMap.emplace(uid, threshold); + mMap.emplace(appId, threshold); } -std::optional SmallAreaDetectionAllowMappings::getThresholdForUid(uid_t uid) { +std::optional SmallAreaDetectionAllowMappings::getThresholdForAppId(int32_t appId) { std::lock_guard lock(mLock); - const auto iter = mMap.find(uid); + const auto iter = mMap.find(appId); if (iter != mMap.end()) { return iter->second; } diff --git a/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h index cbab69091f..e10301c1e8 100644 --- a/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h +++ b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h @@ -24,16 +24,16 @@ namespace android::scheduler { class SmallAreaDetectionAllowMappings { - using UidThresholdMap = std::unordered_map; + using AppIdThresholdMap = std::unordered_map; public: - void update(std::vector>& uidThresholdMappings); - void setThesholdForUid(uid_t uid, float threshold) EXCLUDES(mLock); - std::optional getThresholdForUid(uid_t uid) EXCLUDES(mLock); + void update(std::vector>& appIdThresholdMappings); + void setThesholdForAppId(int32_t appId, float threshold) EXCLUDES(mLock); + std::optional getThresholdForAppId(int32_t uid) EXCLUDES(mLock); private: static bool isValidThreshold(float threshold) { return threshold >= 0.0f && threshold <= 1.0f; } mutable std::mutex mLock; - UidThresholdMap mMap GUARDED_BY(mLock); + AppIdThresholdMap mMap GUARDED_BY(mLock); }; } // namespace android::scheduler diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 38dc435357..ec3050c375 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -8157,13 +8157,13 @@ status_t SurfaceFlinger::setOverrideFrameRate(uid_t uid, float frameRate) { } status_t SurfaceFlinger::updateSmallAreaDetection( - std::vector>& uidThresholdMappings) { - mScheduler->updateSmallAreaDetection(uidThresholdMappings); + std::vector>& appIdThresholdMappings) { + mScheduler->updateSmallAreaDetection(appIdThresholdMappings); return NO_ERROR; } -status_t SurfaceFlinger::setSmallAreaDetectionThreshold(uid_t uid, float threshold) { - mScheduler->setSmallAreaDetectionThreshold(uid, threshold); +status_t SurfaceFlinger::setSmallAreaDetectionThreshold(int32_t appId, float threshold) { + mScheduler->setSmallAreaDetectionThreshold(appId, threshold); return NO_ERROR; } @@ -9530,18 +9530,18 @@ binder::Status SurfaceComposerAIDL::scheduleCommit() { return binder::Status::ok(); } -binder::Status SurfaceComposerAIDL::updateSmallAreaDetection(const std::vector& uids, +binder::Status SurfaceComposerAIDL::updateSmallAreaDetection(const std::vector& appIds, const std::vector& thresholds) { status_t status; const int c_uid = IPCThreadState::self()->getCallingUid(); if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) { - if (uids.size() != thresholds.size()) return binderStatusFromStatusT(BAD_VALUE); + if (appIds.size() != thresholds.size()) return binderStatusFromStatusT(BAD_VALUE); - std::vector> mappings; - const size_t size = uids.size(); + std::vector> mappings; + const size_t size = appIds.size(); mappings.reserve(size); for (int i = 0; i < size; i++) { - auto row = std::make_pair(static_cast(uids[i]), thresholds[i]); + auto row = std::make_pair(appIds[i], thresholds[i]); mappings.push_back(row); } status = mFlinger->updateSmallAreaDetection(mappings); @@ -9552,11 +9552,11 @@ binder::Status SurfaceComposerAIDL::updateSmallAreaDetection(const std::vectorgetCallingUid(); if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) { - status = mFlinger->setSmallAreaDetectionThreshold(uid, threshold); + status = mFlinger->setSmallAreaDetectionThreshold(appId, threshold); } else { ALOGE("setSmallAreaDetectionThreshold() permission denied for uid: %d", c_uid); status = PERMISSION_DENIED; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index dc4e7cf2fe..550319576b 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -606,9 +606,9 @@ private: status_t setOverrideFrameRate(uid_t uid, float frameRate); - status_t updateSmallAreaDetection(std::vector>& uidThresholdMappings); + status_t updateSmallAreaDetection(std::vector>& uidThresholdMappings); - status_t setSmallAreaDetectionThreshold(uid_t uid, float threshold); + status_t setSmallAreaDetectionThreshold(int32_t appId, float threshold); int getGpuContextPriority(); @@ -1560,9 +1560,9 @@ public: binder::Status setDebugFlash(int delay) override; binder::Status scheduleComposite() override; binder::Status scheduleCommit() override; - binder::Status updateSmallAreaDetection(const std::vector& uids, + binder::Status updateSmallAreaDetection(const std::vector& appIds, const std::vector& thresholds) override; - binder::Status setSmallAreaDetectionThreshold(int32_t uid, float threshold) override; + binder::Status setSmallAreaDetectionThreshold(int32_t appId, float threshold) override; binder::Status getGpuContextPriority(int32_t* outPriority) override; binder::Status getMaxAcquiredBufferCount(int32_t* buffers) override; binder::Status addWindowInfosListener(const sp& windowInfosListener, diff --git a/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp b/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp index b910485c06..05f9eed30b 100644 --- a/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp +++ b/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp @@ -23,38 +23,34 @@ namespace android::scheduler { -class SmallAreaDetectionMappingsAllowTest : public testing::Test { +class SmallAreaDetectionAllowMappingsTest : public testing::Test { protected: SmallAreaDetectionAllowMappings mMappings; + static constexpr int32_t kAppId1 = 10100; + static constexpr int32_t kAppId2 = 10101; + static constexpr float kThreshold1 = 0.05f; + static constexpr float kThreshold2 = 0.07f; }; namespace { -TEST_F(SmallAreaDetectionMappingsAllowTest, testUpdate) { - const uid_t uid1 = 10100; - const uid_t uid2 = 10101; - const float threshold1 = 0.05f; - const float threshold2 = 0.07f; - std::vector> mappings; +TEST_F(SmallAreaDetectionAllowMappingsTest, testUpdate) { + std::vector> mappings; mappings.reserve(2); - mappings.push_back(std::make_pair(uid1, threshold1)); - mappings.push_back(std::make_pair(uid2, threshold2)); + mappings.push_back(std::make_pair(kAppId1, kThreshold1)); + mappings.push_back(std::make_pair(kAppId2, kThreshold2)); mMappings.update(mappings); - ASSERT_EQ(mMappings.getThresholdForUid(uid1).value(), threshold1); - ASSERT_EQ(mMappings.getThresholdForUid(uid2).value(), threshold2); + ASSERT_EQ(mMappings.getThresholdForAppId(kAppId1).value(), kThreshold1); + ASSERT_EQ(mMappings.getThresholdForAppId(kAppId2).value(), kThreshold2); } -TEST_F(SmallAreaDetectionMappingsAllowTest, testSetThesholdForUid) { - const uid_t uid = 10111; - const float threshold = 0.05f; - - mMappings.setThesholdForUid(uid, threshold); - ASSERT_EQ(mMappings.getThresholdForUid(uid), threshold); +TEST_F(SmallAreaDetectionAllowMappingsTest, testSetThesholdForAppId) { + mMappings.setThesholdForAppId(kAppId1, kThreshold1); + ASSERT_EQ(mMappings.getThresholdForAppId(kAppId1), kThreshold1); } -TEST_F(SmallAreaDetectionMappingsAllowTest, testUidNotInTheMappings) { - const uid_t uid = 10222; - ASSERT_EQ(mMappings.getThresholdForUid(uid), std::nullopt); +TEST_F(SmallAreaDetectionAllowMappingsTest, testAppIdNotInTheMappings) { + ASSERT_EQ(mMappings.getThresholdForAppId(kAppId1), std::nullopt); } } // namespace -- cgit v1.2.3-59-g8ed1b From 55e3103c33bdb6da73d45be50bff0161e5a5822f Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 2 Oct 2023 20:34:18 +0000 Subject: Rename DisplayMode::refreshRate to peakRefreshRate Peak refresh rate is a more clear name Bug: 301462354 Test: builds, boots Test: dumpsys display Change-Id: I2f7f98859ae2a1d9191b1e377921eb7a04e784bf --- libs/gui/SurfaceComposerClient.cpp | 2 +- libs/gui/aidl/android/gui/DisplayMode.aidl | 2 +- libs/gui/tests/EndToEndNativeInputTest.cpp | 2 +- libs/nativedisplay/ADisplay.cpp | 2 +- libs/ui/include/ui/DisplayMode.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 10 +++++----- services/surfaceflinger/tests/DisplayConfigs_test.cpp | 4 ++-- services/surfaceflinger/tests/LayerTransactionTest.h | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 05e2ddf198..a3518110cd 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2604,7 +2604,7 @@ void SurfaceComposerClient::getDynamicDisplayInfoInternal(gui::DynamicDisplayInf outMode.resolution.height = mode.resolution.height; outMode.xDpi = mode.xDpi; outMode.yDpi = mode.yDpi; - outMode.refreshRate = mode.refreshRate; + outMode.peakRefreshRate = mode.peakRefreshRate; outMode.vsyncRate = mode.vsyncRate; outMode.appVsyncOffset = mode.appVsyncOffset; outMode.sfVsyncOffset = mode.sfVsyncOffset; diff --git a/libs/gui/aidl/android/gui/DisplayMode.aidl b/libs/gui/aidl/android/gui/DisplayMode.aidl index b057653200..f605177cfd 100644 --- a/libs/gui/aidl/android/gui/DisplayMode.aidl +++ b/libs/gui/aidl/android/gui/DisplayMode.aidl @@ -30,7 +30,7 @@ parcelable DisplayMode { int[] supportedHdrTypes; // Some modes have peak refresh rate lower than the panel vsync rate. - float refreshRate = 0.0f; + float peakRefreshRate = 0.0f; float vsyncRate = 0.0f; long appVsyncOffset = 0; long sfVsyncOffset = 0; diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 662e9fe74a..d4b8dbeeb9 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -394,7 +394,7 @@ public: // After a new buffer is queued, SurfaceFlinger is notified and will // latch the new buffer on next vsync. Let's heuristically wait for 3 // vsyncs. - mBufferPostDelay = static_cast(1e6 / mode.refreshRate) * 3; + mBufferPostDelay = static_cast(1e6 / mode.peakRefreshRate) * 3; } void TearDown() { diff --git a/libs/nativedisplay/ADisplay.cpp b/libs/nativedisplay/ADisplay.cpp index bf0805b46c..e3be3bc8f8 100644 --- a/libs/nativedisplay/ADisplay.cpp +++ b/libs/nativedisplay/ADisplay.cpp @@ -155,7 +155,7 @@ int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays) { const ui::DisplayMode& mode = modes[j]; modesPerDisplay[i].emplace_back( DisplayConfigImpl{static_cast(mode.id), mode.resolution.getWidth(), - mode.resolution.getHeight(), mode.refreshRate, + mode.resolution.getHeight(), mode.peakRefreshRate, mode.sfVsyncOffset, mode.appVsyncOffset}); } } diff --git a/libs/ui/include/ui/DisplayMode.h b/libs/ui/include/ui/DisplayMode.h index a469c78070..ddb9bbd4bc 100644 --- a/libs/ui/include/ui/DisplayMode.h +++ b/libs/ui/include/ui/DisplayMode.h @@ -38,7 +38,7 @@ struct DisplayMode { std::vector supportedHdrTypes; // Some modes have peak refresh rate lower than the panel vsync rate. - float refreshRate = 0.f; + float peakRefreshRate = 0.f; float vsyncRate = 0.f; nsecs_t appVsyncOffset = 0; nsecs_t sfVsyncOffset = 0; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9b9a67aa5f..fc517212ea 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -266,7 +266,7 @@ bool getKernelIdleTimerSyspropConfig(DisplayId displayId) { bool isAbove4k30(const ui::DisplayMode& outMode) { using fps_approx_ops::operator>; - Fps refreshRate = Fps::fromValue(outMode.refreshRate); + Fps refreshRate = Fps::fromValue(outMode.peakRefreshRate); return outMode.resolution.getWidth() >= FOUR_K_WIDTH && outMode.resolution.getHeight() >= FOUR_K_HEIGHT && refreshRate > 30_Hz; } @@ -1046,11 +1046,11 @@ void SurfaceFlinger::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo*& info outMode.yDpi = yDpi; const auto peakFps = mode->getPeakFps(); - outMode.refreshRate = peakFps.getValue(); + outMode.peakRefreshRate = peakFps.getValue(); outMode.vsyncRate = mode->getVsyncRate().getValue(); - const auto vsyncConfigSet = - mVsyncConfiguration->getConfigsForRefreshRate(Fps::fromValue(outMode.refreshRate)); + const auto vsyncConfigSet = mVsyncConfiguration->getConfigsForRefreshRate( + Fps::fromValue(outMode.peakRefreshRate)); outMode.appVsyncOffset = vsyncConfigSet.late.appOffset; outMode.sfVsyncOffset = vsyncConfigSet.late.sfOffset; outMode.group = mode->getGroup(); @@ -9221,7 +9221,7 @@ void SurfaceComposerAIDL::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo& outMode.resolution.height = mode.resolution.height; outMode.xDpi = mode.xDpi; outMode.yDpi = mode.yDpi; - outMode.refreshRate = mode.refreshRate; + outMode.peakRefreshRate = mode.peakRefreshRate; outMode.vsyncRate = mode.vsyncRate; outMode.appVsyncOffset = mode.appVsyncOffset; outMode.sfVsyncOffset = mode.sfVsyncOffset; diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp index 4be961bda1..0a951d49e3 100644 --- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp +++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp @@ -75,8 +75,8 @@ TEST_F(RefreshRateRangeTest, setAllConfigs) { setSpecs.allowGroupSwitching = false; for (size_t i = 0; i < modes.size(); i++) { setSpecs.defaultMode = modes[i].id; - setSpecs.primaryRanges.physical.min = modes[i].refreshRate; - setSpecs.primaryRanges.physical.max = modes[i].refreshRate; + setSpecs.primaryRanges.physical.min = modes[i].peakRefreshRate; + setSpecs.primaryRanges.physical.max = modes[i].peakRefreshRate; setSpecs.primaryRanges.render = setSpecs.primaryRanges.physical; setSpecs.appRequestRanges = setSpecs.primaryRanges; res = SurfaceComposerClient::setDesiredDisplayModeSpecs(mDisplayToken, setSpecs); diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index 2bdb8a452d..9269e7c8a0 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -299,7 +299,7 @@ private: // After a new buffer is queued, SurfaceFlinger is notified and will // latch the new buffer on next vsync. Let's heuristically wait for 3 // vsyncs. - mBufferPostDelay = static_cast(1e6 / mode.refreshRate) * 3; + mBufferPostDelay = static_cast(1e6 / mode.peakRefreshRate) * 3; mBlackBgSurface = createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */, -- cgit v1.2.3-59-g8ed1b From 7e4c4872b792d59b6ba00dd54f2ead8e8de9ca0c Mon Sep 17 00:00:00 2001 From: John Reck Date: Tue, 14 Nov 2023 18:31:03 -0500 Subject: Add capture args to captureDisplayById Test: make && screencap Change-Id: I509bd458ee2fc712cf1d978caa8dac8d14154045 --- libs/gui/SurfaceComposerClient.cpp | 4 ++-- libs/gui/aidl/android/gui/CaptureArgs.aidl | 19 +++++++++++++++++ libs/gui/aidl/android/gui/ISurfaceComposer.aidl | 4 +++- libs/gui/fuzzer/libgui_fuzzer_utils.h | 4 ++-- libs/gui/include/gui/SurfaceComposerClient.h | 8 ++++++- libs/gui/tests/Surface_test.cpp | 3 ++- services/surfaceflinger/SurfaceFlinger.cpp | 28 ++++++++++++++++++------- services/surfaceflinger/SurfaceFlinger.h | 5 +++-- 8 files changed, 59 insertions(+), 16 deletions(-) create mode 100644 libs/gui/aidl/android/gui/CaptureArgs.aidl (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index a3518110cd..922b0ddcde 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -3122,12 +3122,12 @@ status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs, return statusTFromBinderStatus(status); } -status_t ScreenshotClient::captureDisplay(DisplayId displayId, +status_t ScreenshotClient::captureDisplay(DisplayId displayId, const gui::CaptureArgs& captureArgs, const sp& captureListener) { sp s(ComposerServiceAIDL::getComposerService()); if (s == nullptr) return NO_INIT; - binder::Status status = s->captureDisplayById(displayId.value, captureListener); + binder::Status status = s->captureDisplayById(displayId.value, captureArgs, captureListener); return statusTFromBinderStatus(status); } diff --git a/libs/gui/aidl/android/gui/CaptureArgs.aidl b/libs/gui/aidl/android/gui/CaptureArgs.aidl new file mode 100644 index 0000000000..920d94980a --- /dev/null +++ b/libs/gui/aidl/android/gui/CaptureArgs.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2023 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. + */ + +package android.gui; + +parcelable CaptureArgs cpp_header "gui/DisplayCaptureArgs.h"; diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index a7cf5ddeb4..265373c6e0 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -16,6 +16,7 @@ package android.gui; +import android.gui.CaptureArgs; import android.gui.Color; import android.gui.CompositionPreference; import android.gui.ContentSamplingAttributes; @@ -238,7 +239,8 @@ interface ISurfaceComposer { * Capture the specified screen. This requires the READ_FRAME_BUFFER * permission. */ - oneway void captureDisplayById(long displayId, IScreenCaptureListener listener); + oneway void captureDisplayById(long displayId, in CaptureArgs args, + IScreenCaptureListener listener); /** * Capture a subtree of the layer hierarchy, potentially ignoring the root node. diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h index 3142103d17..065ba06e38 100644 --- a/libs/gui/fuzzer/libgui_fuzzer_utils.h +++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h @@ -100,8 +100,8 @@ public: MOCK_METHOD(binder::Status, setGameContentType, (const sp&, bool), (override)); MOCK_METHOD(binder::Status, captureDisplay, (const DisplayCaptureArgs&, const sp&), (override)); - MOCK_METHOD(binder::Status, captureDisplayById, (int64_t, const sp&), - (override)); + MOCK_METHOD(binder::Status, captureDisplayById, + (int64_t, const gui::CaptureArgs&, const sp&), (override)); MOCK_METHOD(binder::Status, captureLayers, (const LayerCaptureArgs&, const sp&), (override)); MOCK_METHOD(binder::Status, clearAnimationFrameStats, (), (override)); diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 54c3aa7c1c..5bf6c473d9 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -841,8 +841,14 @@ private: class ScreenshotClient { public: static status_t captureDisplay(const DisplayCaptureArgs&, const sp&); - static status_t captureDisplay(DisplayId, const sp&); + static status_t captureDisplay(DisplayId, const gui::CaptureArgs&, + const sp&); static status_t captureLayers(const LayerCaptureArgs&, const sp&); + + [[deprecated]] static status_t captureDisplay(DisplayId id, + const sp& listener) { + return captureDisplay(id, gui::CaptureArgs(), listener); + } }; // --------------------------------------------------------------------------- diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 0e26544b87..8d3eacba90 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -786,7 +786,8 @@ public: return binder::Status::ok(); } - binder::Status captureDisplayById(int64_t, const sp&) override { + binder::Status captureDisplayById(int64_t, const gui::CaptureArgs&, + const sp&) override { return binder::Status::ok(); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9c8555eb62..2dd035b1c5 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -7582,7 +7582,7 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, args.allowProtected, args.grayscale, captureListener); } -void SurfaceFlinger::captureDisplay(DisplayId displayId, +void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args, const sp& captureListener) { ui::LayerStack layerStack; wp displayWeak; @@ -7601,10 +7601,23 @@ void SurfaceFlinger::captureDisplay(DisplayId displayId, size = display->getLayerStackSpaceRect().getSize(); } + size.width *= args.frameScaleX; + size.height *= args.frameScaleY; + + // We could query a real value for this but it'll be a long, long time until we support + // displays that need upwards of 1GB per buffer so... + constexpr auto kMaxTextureSize = 16384; + if (size.width <= 0 || size.height <= 0 || size.width >= kMaxTextureSize || + size.height >= kMaxTextureSize) { + ALOGE("capture display resolved to invalid size %d x %d", size.width, size.height); + invokeScreenCaptureError(BAD_VALUE, captureListener); + return; + } + RenderAreaFuture renderAreaFuture = ftl::defer([=] { - return DisplayRenderArea::create(displayWeak, Rect(), size, ui::Dataspace::UNKNOWN, + return DisplayRenderArea::create(displayWeak, Rect(), size, args.dataspace, false /* useIdentityTransform */, - false /* hintForSeamlessTransition */, + args.hintForSeamlessTransition, false /* captureSecureLayers */); }); @@ -7628,8 +7641,8 @@ void SurfaceFlinger::captureDisplay(DisplayId displayId, constexpr bool kAllowProtected = false; constexpr bool kGrayscale = false; - captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, size, - ui::PixelFormat::RGBA_8888, kAllowProtected, kGrayscale, captureListener); + captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, size, args.pixelFormat, + kAllowProtected, kGrayscale, captureListener); } void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, @@ -9423,13 +9436,14 @@ binder::Status SurfaceComposerAIDL::captureDisplay( } binder::Status SurfaceComposerAIDL::captureDisplayById( - int64_t displayId, const sp& captureListener) { + int64_t displayId, const CaptureArgs& args, + const sp& captureListener) { // status_t status; IPCThreadState* ipc = IPCThreadState::self(); const int uid = ipc->getCallingUid(); if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) { std::optional id = DisplayId::fromValue(static_cast(displayId)); - mFlinger->captureDisplay(*id, captureListener); + mFlinger->captureDisplay(*id, args, captureListener); } else { invokeScreenCaptureError(PERMISSION_DENIED, captureListener); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 1e90340449..9177a5bbcd 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -531,7 +531,7 @@ private: const sp& layerHandle = nullptr); void captureDisplay(const DisplayCaptureArgs&, const sp&); - void captureDisplay(DisplayId, const sp&); + void captureDisplay(DisplayId, const CaptureArgs&, const sp&); void captureLayers(const LayerCaptureArgs&, const sp&); status_t getDisplayStats(const sp& displayToken, DisplayStatInfo* stats); @@ -1507,7 +1507,8 @@ public: binder::Status setGameContentType(const sp& display, bool on) override; binder::Status captureDisplay(const DisplayCaptureArgs&, const sp&) override; - binder::Status captureDisplayById(int64_t, const sp&) override; + binder::Status captureDisplayById(int64_t, const CaptureArgs&, + const sp&) override; binder::Status captureLayers(const LayerCaptureArgs&, const sp&) override; -- cgit v1.2.3-59-g8ed1b From 8c2703dfc85c911d28111f5b1e54ee8acb7fcbb2 Mon Sep 17 00:00:00 2001 From: Andy Yu Date: Fri, 3 Nov 2023 11:22:46 -0700 Subject: 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 --- libs/gui/SurfaceComposerClient.cpp | 11 ++- libs/gui/aidl/android/gui/ISurfaceComposer.aidl | 13 ++- libs/gui/fuzzer/libgui_fuzzer_utils.h | 3 +- libs/gui/include/gui/SurfaceComposerClient.h | 8 +- libs/gui/tests/Surface_test.cpp | 6 +- .../Scheduler/FrameRateOverrideMappings.cpp | 18 ++-- services/surfaceflinger/Scheduler/LayerHistory.cpp | 91 +++++++++++++++++- services/surfaceflinger/Scheduler/LayerHistory.h | 17 ++++ services/surfaceflinger/Scheduler/LayerInfo.h | 3 +- services/surfaceflinger/Scheduler/Scheduler.cpp | 19 +++- services/surfaceflinger/Scheduler/Scheduler.h | 12 ++- services/surfaceflinger/SurfaceFlinger.cpp | 30 +++++- services/surfaceflinger/SurfaceFlinger.h | 7 +- services/surfaceflinger/common/FlagManager.cpp | 2 + .../common/include/common/FlagManager.h | 1 + .../surfaceflinger/surfaceflinger_flags.aconfig | 8 ++ services/surfaceflinger/tests/Android.bp | 1 - .../tests/SetFrameRateOverride_test.cpp | 100 -------------------- .../unittests/FrameRateOverrideMappingsTest.cpp | 8 +- .../tests/unittests/LayerHistoryTest.cpp | 102 +++++++++++++++++++++ .../tests/unittests/mock/MockLayer.h | 8 ++ 21 files changed, 338 insertions(+), 130 deletions(-) delete mode 100644 services/surfaceflinger/tests/SetFrameRateOverride_test.cpp (limited to 'libs/gui/SurfaceComposerClient.cpp') 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&, std::optional*), (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 namespace android::scheduler { using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; @@ -30,7 +31,7 @@ std::optional 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 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 LayerHistory::getGameFrameRateOverride(uid_t uid) const { + if (!FlagManager::getInstance().game_default_frame_rate()) { + return std::pair(); + } + + std::lock_guard lock(mLock); + + return getGameFrameRateOverrideLocked(uid); +} + +std::pair LayerHistory::getGameFrameRateOverrideLocked(uid_t uid) const { + if (!FlagManager::getInstance().game_default_frame_rate()) { + return std::pair(); + } + + const auto it = mGameFrameRateOverride.find(uid); + + if (it == mGameFrameRateOverride.end()) { + return std::pair(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 getGameFrameRateOverride(uid_t uid) const EXCLUDES(mLock); + std::pair 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 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> 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>& 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& 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), frameRate}); + mScheduler->setGameModeFrameRateForUid(FrameRateOverride{static_cast(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), frameRate}); + } + return NO_ERROR; +} + status_t SurfaceFlinger::updateSmallAreaDetection( std::vector>& 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& 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>& uidThresholdMappings); @@ -1571,7 +1573,8 @@ public: binder::Status getDisplayDecorationSupport( const sp& displayToken, std::optional* 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 -#include -#include -#include -#include -#include - -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(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 mDisplayEventReceiver; - std::vector 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 +#include #include #include @@ -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::make(mFlinger.flinger(), std::move(name)); } + auto createLayer(std::string name, uint32_t uid) { + return sp::make(mFlinger.flinger(), std::move(name), std::move(uid)); + } void recordFramesAndExpect(const sp& 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 +#include 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 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*()); -- cgit v1.2.3-59-g8ed1b