• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <chrono>
20 #include <mutex>
21 #include <optional>
22 #include <unordered_set>
23 
24 #include <android-base/thread_annotations.h>
25 #include <binder/IBinder.h>
26 #include <utils/Timers.h>
27 
28 namespace android::scheduler {
29 
30 // State machine controlled by transaction flags. VsyncModulator switches to early phase offsets
31 // when a transaction is flagged EarlyStart or Early, lasting until an EarlyEnd transaction or a
32 // fixed number of frames, respectively.
33 enum class TransactionSchedule {
34     Late,  // Default.
35     EarlyStart,
36     EarlyEnd
37 };
38 
39 // Modulates VSYNC phase depending on transaction schedule and refresh rate changes.
40 class VsyncModulator : public IBinder::DeathRecipient {
41 public:
42     // Number of frames to keep early offsets after an early transaction or GPU composition.
43     // This acts as a low-pass filter in case subsequent transactions are delayed, or if the
44     // composition strategy alternates on subsequent frames.
45     static constexpr int MIN_EARLY_TRANSACTION_FRAMES = 2;
46     static constexpr int MIN_EARLY_GPU_FRAMES = 2;
47 
48     // Duration to delay the MIN_EARLY_TRANSACTION_FRAMES countdown after an early transaction.
49     // This may keep early offsets for an extra frame, but avoids a race with transaction commit.
50     static const std::chrono::nanoseconds MIN_EARLY_TRANSACTION_TIME;
51 
52     // Phase offsets and work durations for SF and app deadlines from VSYNC.
53     struct VsyncConfig {
54         nsecs_t sfOffset;
55         nsecs_t appOffset;
56         std::chrono::nanoseconds sfWorkDuration;
57         std::chrono::nanoseconds appWorkDuration;
58 
59         bool operator==(const VsyncConfig& other) const {
60             return sfOffset == other.sfOffset && appOffset == other.appOffset &&
61                     sfWorkDuration == other.sfWorkDuration &&
62                     appWorkDuration == other.appWorkDuration;
63         }
64 
65         bool operator!=(const VsyncConfig& other) const { return !(*this == other); }
66     };
67 
68     using VsyncConfigOpt = std::optional<VsyncConfig>;
69 
70     struct VsyncConfigSet {
71         VsyncConfig early;    // Used for early transactions, and during refresh rate change.
72         VsyncConfig earlyGpu; // Used during GPU composition.
73         VsyncConfig late;     // Default.
74         std::chrono::nanoseconds hwcMinWorkDuration; // Used for calculating the
75                                                      // earliest present time
76 
77         bool operator==(const VsyncConfigSet& other) const {
78             return early == other.early && earlyGpu == other.earlyGpu && late == other.late &&
79                     hwcMinWorkDuration == other.hwcMinWorkDuration;
80         }
81 
82         bool operator!=(const VsyncConfigSet& other) const { return !(*this == other); }
83     };
84 
85     using Clock = std::chrono::steady_clock;
86     using TimePoint = Clock::time_point;
87     using Now = TimePoint (*)();
88 
89     explicit VsyncModulator(const VsyncConfigSet&, Now = Clock::now);
90 
91     VsyncConfig getVsyncConfig() const EXCLUDES(mMutex);
92 
93     [[nodiscard]] VsyncConfig setVsyncConfigSet(const VsyncConfigSet&) EXCLUDES(mMutex);
94 
95     // Changes offsets in response to transaction flags or commit.
96     [[nodiscard]] VsyncConfigOpt setTransactionSchedule(TransactionSchedule,
97                                                         const sp<IBinder>& = {}) EXCLUDES(mMutex);
98     [[nodiscard]] VsyncConfigOpt onTransactionCommit();
99 
100     // Called when we send a refresh rate change to hardware composer, so that
101     // we can move into early offsets.
102     [[nodiscard]] VsyncConfigOpt onRefreshRateChangeInitiated();
103 
104     // Called when we detect from VSYNC signals that the refresh rate changed.
105     // This way we can move out of early offsets if no longer necessary.
106     [[nodiscard]] VsyncConfigOpt onRefreshRateChangeCompleted();
107 
108     [[nodiscard]] VsyncConfigOpt onDisplayRefresh(bool usedGpuComposition);
109 
110 protected:
111     // Called from unit tests as well
112     void binderDied(const wp<IBinder>&) override EXCLUDES(mMutex);
113 
114 private:
115     const VsyncConfig& getNextVsyncConfig() const REQUIRES(mMutex);
116     [[nodiscard]] VsyncConfig updateVsyncConfig() EXCLUDES(mMutex);
117     [[nodiscard]] VsyncConfig updateVsyncConfigLocked() REQUIRES(mMutex);
118 
119     mutable std::mutex mMutex;
120     VsyncConfigSet mVsyncConfigSet GUARDED_BY(mMutex);
121 
GUARDED_BY(mMutex)122     VsyncConfig mVsyncConfig GUARDED_BY(mMutex){mVsyncConfigSet.late};
123 
124     using Schedule = TransactionSchedule;
125     std::atomic<Schedule> mTransactionSchedule = Schedule::Late;
126 
127     struct WpHash {
operatorWpHash128         size_t operator()(const wp<IBinder>& p) const {
129             return std::hash<IBinder*>()(p.unsafe_get());
130         }
131     };
132 
133     std::unordered_set<wp<IBinder>, WpHash> mEarlyWakeupRequests GUARDED_BY(mMutex);
134     std::atomic<bool> mRefreshRateChangePending = false;
135 
136     std::atomic<int> mEarlyTransactionFrames = 0;
137     std::atomic<int> mEarlyGpuFrames = 0;
138     std::atomic<TimePoint> mEarlyTransactionStartTime = TimePoint();
139     std::atomic<TimePoint> mLastTransactionCommitTime = TimePoint();
140 
141     const Now mNow;
142     const bool mTraceDetailedInfo;
143 };
144 
145 } // namespace android::scheduler
146