xref: /aosp_15_r20/frameworks/native/services/surfaceflinger/Scheduler/VsyncModulator.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 /*
2  * Copyright 2019 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 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
18 
19 #undef LOG_TAG
20 #define LOG_TAG "VsyncModulator"
21 
22 #include "VsyncModulator.h"
23 
24 #include <common/trace.h>
25 #include <log/log.h>
26 
27 #include <chrono>
28 #include <cinttypes>
29 #include <mutex>
30 
31 using namespace std::chrono_literals;
32 
33 namespace android::scheduler {
34 
35 const std::chrono::nanoseconds VsyncModulator::MIN_EARLY_TRANSACTION_TIME = 1ms;
36 
VsyncModulator(const VsyncConfigSet & config,Now now)37 VsyncModulator::VsyncModulator(const VsyncConfigSet& config, Now now)
38       : mVsyncConfigSet(config),
39         mNow(now) {}
40 
setVsyncConfigSet(const VsyncConfigSet & config)41 VsyncConfig VsyncModulator::setVsyncConfigSet(const VsyncConfigSet& config) {
42     std::lock_guard<std::mutex> lock(mMutex);
43     mVsyncConfigSet = config;
44     return updateVsyncConfigLocked();
45 }
46 
setTransactionSchedule(TransactionSchedule schedule,const sp<IBinder> & token)47 VsyncModulator::VsyncConfigOpt VsyncModulator::setTransactionSchedule(TransactionSchedule schedule,
48                                                                       const sp<IBinder>& token) {
49     std::lock_guard<std::mutex> lock(mMutex);
50     switch (schedule) {
51         case Schedule::EarlyStart:
52             if (token) {
53                 mEarlyWakeupRequests.emplace(token);
54                 token->linkToDeath(sp<DeathRecipient>::fromExisting(this));
55             } else {
56                 ALOGW("%s: EarlyStart requested without a valid token", __func__);
57             }
58             break;
59         case Schedule::EarlyEnd: {
60             if (token && mEarlyWakeupRequests.erase(token) > 0) {
61                 token->unlinkToDeath(sp<DeathRecipient>::fromExisting(this));
62             } else {
63                 ALOGW("%s: Unexpected EarlyEnd", __func__);
64             }
65             break;
66         }
67         case Schedule::Late:
68             // No change to mEarlyWakeup for non-explicit states.
69             break;
70     }
71 
72     if (mEarlyWakeupRequests.empty() && schedule == Schedule::EarlyEnd) {
73         mEarlyTransactionFrames = MIN_EARLY_TRANSACTION_FRAMES;
74         mEarlyTransactionStartTime = mNow();
75     }
76 
77     // An early transaction stays an early transaction.
78     if (schedule == mTransactionSchedule || mTransactionSchedule == Schedule::EarlyEnd) {
79         return std::nullopt;
80     }
81     mTransactionSchedule = schedule;
82     return updateVsyncConfigLocked();
83 }
84 
onTransactionCommit()85 VsyncModulator::VsyncConfigOpt VsyncModulator::onTransactionCommit() {
86     mLastTransactionCommitTime = mNow();
87     if (mTransactionSchedule == Schedule::Late) return std::nullopt;
88     mTransactionSchedule = Schedule::Late;
89     return updateVsyncConfig();
90 }
91 
onRefreshRateChangeInitiated()92 VsyncModulator::VsyncConfigOpt VsyncModulator::onRefreshRateChangeInitiated() {
93     if (mRefreshRateChangePending) return std::nullopt;
94     mRefreshRateChangePending = true;
95     return updateVsyncConfig();
96 }
97 
onRefreshRateChangeCompleted()98 VsyncModulator::VsyncConfigOpt VsyncModulator::onRefreshRateChangeCompleted() {
99     if (!mRefreshRateChangePending) return std::nullopt;
100     mRefreshRateChangePending = false;
101     return updateVsyncConfig();
102 }
103 
onDisplayRefresh(bool usedGpuComposition)104 VsyncModulator::VsyncConfigOpt VsyncModulator::onDisplayRefresh(bool usedGpuComposition) {
105     bool updateOffsetsNeeded = false;
106 
107     if (mEarlyTransactionStartTime.load() + MIN_EARLY_TRANSACTION_TIME <=
108         mLastTransactionCommitTime.load()) {
109         if (mEarlyTransactionFrames > 0) {
110             mEarlyTransactionFrames--;
111             updateOffsetsNeeded = true;
112         }
113     }
114     if (usedGpuComposition) {
115         mEarlyGpuFrames = MIN_EARLY_GPU_FRAMES;
116         updateOffsetsNeeded = true;
117     } else if (mEarlyGpuFrames > 0) {
118         mEarlyGpuFrames--;
119         updateOffsetsNeeded = true;
120     }
121 
122     if (!updateOffsetsNeeded) return std::nullopt;
123     return updateVsyncConfig();
124 }
125 
getVsyncConfig() const126 VsyncConfig VsyncModulator::getVsyncConfig() const {
127     std::lock_guard<std::mutex> lock(mMutex);
128     return mVsyncConfig;
129 }
130 
getNextVsyncConfigType() const131 auto VsyncModulator::getNextVsyncConfigType() const -> VsyncConfigType {
132     // Early offsets are used if we're in the middle of a refresh rate
133     // change, or if we recently begin a transaction.
134     if (!mEarlyWakeupRequests.empty() || mTransactionSchedule == Schedule::EarlyEnd ||
135         mEarlyTransactionFrames > 0 || mRefreshRateChangePending) {
136         return VsyncConfigType::Early;
137     } else if (mEarlyGpuFrames > 0) {
138         return VsyncConfigType::EarlyGpu;
139     } else {
140         return VsyncConfigType::Late;
141     }
142 }
143 
getNextVsyncConfig() const144 const VsyncConfig& VsyncModulator::getNextVsyncConfig() const {
145     switch (getNextVsyncConfigType()) {
146         case VsyncConfigType::Early:
147             return mVsyncConfigSet.early;
148         case VsyncConfigType::EarlyGpu:
149             return mVsyncConfigSet.earlyGpu;
150         case VsyncConfigType::Late:
151             return mVsyncConfigSet.late;
152     }
153 }
154 
updateVsyncConfig()155 VsyncConfig VsyncModulator::updateVsyncConfig() {
156     std::lock_guard<std::mutex> lock(mMutex);
157     return updateVsyncConfigLocked();
158 }
159 
updateVsyncConfigLocked()160 VsyncConfig VsyncModulator::updateVsyncConfigLocked() {
161     const VsyncConfig& offsets = getNextVsyncConfig();
162     mVsyncConfig = offsets;
163 
164     // Trace config type
165     SFTRACE_INT("Vsync-Early",  &mVsyncConfig == &mVsyncConfigSet.early);
166     SFTRACE_INT("Vsync-EarlyGpu", &mVsyncConfig == &mVsyncConfigSet.earlyGpu);
167     SFTRACE_INT("Vsync-Late", &mVsyncConfig == &mVsyncConfigSet.late);
168 
169     // Trace early vsync conditions
170     SFTRACE_INT("EarlyWakeupRequests",
171                                  static_cast<int>(mEarlyWakeupRequests.size()));
172     SFTRACE_INT("EarlyTransactionFrames", mEarlyTransactionFrames);
173     SFTRACE_INT("RefreshRateChangePending", mRefreshRateChangePending);
174 
175     // Trace early gpu conditions
176     SFTRACE_INT("EarlyGpuFrames", mEarlyGpuFrames);
177 
178     return offsets;
179 }
180 
binderDied(const wp<IBinder> & who)181 void VsyncModulator::binderDied(const wp<IBinder>& who) {
182     std::lock_guard<std::mutex> lock(mMutex);
183     mEarlyWakeupRequests.erase(who);
184     static_cast<void>(updateVsyncConfigLocked());
185 }
186 
isVsyncConfigEarly() const187 bool VsyncModulator::isVsyncConfigEarly() const {
188     std::lock_guard<std::mutex> lock(mMutex);
189     return getNextVsyncConfigType() != VsyncConfigType::Late;
190 }
191 
192 } // namespace android::scheduler
193