SurfaceFlinger: enhance refresh rate selection
Enhance the refresh rate selection algorithm to allow having multiple
refresh rate. The new process attaches scores to each one of the available
refresh rate and chooses the refresh rate with the highest score.
This behavior is currently controlled by the sysprop flag
'debug.sf.use_content_detection_v2' and currently turned off.
This algorithm stills needs some tunings which will be done in
layer CLs.
Test: adb shell /data/nativetest64/SurfaceFlinger_test/SurfaceFlinger_test
Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest
Test: go/90hzscenarios manual tests
Bug: 147516364
Fixes: 146068419
Change-Id: I06e07459e469482799ff80fa54fa8dd311325e0e
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h
new file mode 100644
index 0000000..564f05e
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2020 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 <utils/Timers.h>
+
+#include <chrono>
+#include <deque>
+
+#include "LayerHistory.h"
+#include "RefreshRateConfigs.h"
+#include "SchedulerUtils.h"
+
+namespace android {
+
+class Layer;
+
+namespace scheduler {
+
+using namespace std::chrono_literals;
+
+// Maximum period between presents for a layer to be considered active.
+constexpr std::chrono::nanoseconds MAX_ACTIVE_LAYER_PERIOD_NS = 1200ms;
+
+// Earliest present time for a layer to be considered active.
+constexpr nsecs_t getActiveLayerThreshold(nsecs_t now) {
+ return now - MAX_ACTIVE_LAYER_PERIOD_NS.count();
+}
+
+// Stores history of present times and refresh rates for a layer.
+class LayerInfoV2 {
+ // Layer is considered frequent if the earliest value in the window of most recent present times
+ // is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in
+ // favor of a low refresh rate.
+ static constexpr size_t FREQUENT_LAYER_WINDOW_SIZE = 3;
+ static constexpr std::chrono::nanoseconds MAX_FREQUENT_LAYER_PERIOD_NS = 250ms;
+
+ friend class LayerHistoryTestV2;
+
+public:
+ LayerInfoV2(nsecs_t highRefreshRatePeriod, LayerHistory::LayerVoteType defaultVote);
+
+ LayerInfoV2(const LayerInfo&) = delete;
+ LayerInfoV2& operator=(const LayerInfoV2&) = delete;
+
+ // Records the last requested present time. It also stores information about when
+ // the layer was last updated. If the present time is farther in the future than the
+ // updated time, the updated time is the present time.
+ void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now);
+
+ bool isRecentlyActive(nsecs_t now) const;
+
+ // Sets an explicit layer vote. This usually comes directly from the application via
+ // ANativeWindow_setFrameRate API
+ void setLayerVote(LayerHistory::LayerVoteType type, float fps) { mLayerVote = {type, fps}; }
+
+ // Sets the default layer vote. This will be the layer vote after calling to resetLayerVote().
+ // This is used for layers that called to setLayerVote() and then removed the vote, so that the
+ // layer can go back to whatever vote it had before the app voted for it.
+ void setDefaultLayerVote(LayerHistory::LayerVoteType type) { mDefaultVote = type; }
+
+ // Resets the layer vote to its default.
+ void resetLayerVote() { mLayerVote = {mDefaultVote, 0.0f}; }
+
+ std::pair<LayerHistory::LayerVoteType, float> getRefreshRate(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.
+ nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; }
+
+ void clearHistory() { mFrameTimes.clear(); }
+
+private:
+ bool isFrequent(nsecs_t now) const;
+ bool hasEnoughDataForHeuristic() const;
+ std::optional<float> calculateRefreshRateIfPossible();
+
+ // Used for sanitizing the heuristic data
+ const nsecs_t mHighRefreshRatePeriod;
+ LayerHistory::LayerVoteType mDefaultVote;
+
+ nsecs_t mLastUpdatedTime = 0;
+
+ float mLastReportedRefreshRate = 0.0f;
+
+ // Holds information about the layer vote
+ struct {
+ LayerHistory::LayerVoteType type;
+ float fps;
+ } mLayerVote;
+
+ // Used to store the layer timestamps
+ struct FrameTimeData {
+ nsecs_t presetTime; // desiredPresentTime, if provided
+ nsecs_t queueTime; // buffer queue time
+ };
+ std::deque<FrameTimeData> mFrameTimes;
+ static constexpr size_t HISTORY_SIZE = 90;
+ static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s;
+};
+
+} // namespace scheduler
+} // namespace android