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 #include "VSyncModulator.h"
20
21 #include <cutils/properties.h>
22 #include <utils/Trace.h>
23
24 #include <cinttypes>
25 #include <mutex>
26
27 namespace android {
28
29 using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
VSyncModulator()30 VSyncModulator::VSyncModulator() {
31 char value[PROPERTY_VALUE_MAX];
32 property_get("debug.sf.vsync_trace_detailed_info", value, "0");
33 mTraceDetailedInfo = atoi(value);
34 // Populate the offset map with some default offsets.
35 const Offsets defaultOffsets = {RefreshRateType::DEFAULT, 0, 0};
36 setPhaseOffsets(defaultOffsets, defaultOffsets, defaultOffsets, 0);
37 }
38
setPhaseOffsets(Offsets early,Offsets earlyGl,Offsets late,nsecs_t thresholdForNextVsync)39 void VSyncModulator::setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late,
40 nsecs_t thresholdForNextVsync) {
41 std::lock_guard<std::mutex> lock(mMutex);
42 mOffsetMap.insert_or_assign(OffsetType::Early, early);
43 mOffsetMap.insert_or_assign(OffsetType::EarlyGl, earlyGl);
44 mOffsetMap.insert_or_assign(OffsetType::Late, late);
45 mThresholdForNextVsync = thresholdForNextVsync;
46 updateOffsetsLocked();
47 }
48
setTransactionStart(Scheduler::TransactionStart transactionStart)49 void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) {
50 if (transactionStart == Scheduler::TransactionStart::EARLY) {
51 mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION;
52 }
53
54 // An early transaction stays an early transaction.
55 if (transactionStart == mTransactionStart ||
56 mTransactionStart == Scheduler::TransactionStart::EARLY) {
57 return;
58 }
59 mTransactionStart = transactionStart;
60 updateOffsets();
61 }
62
onTransactionHandled()63 void VSyncModulator::onTransactionHandled() {
64 if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return;
65 mTransactionStart = Scheduler::TransactionStart::NORMAL;
66 updateOffsets();
67 }
68
onRefreshRateChangeInitiated()69 void VSyncModulator::onRefreshRateChangeInitiated() {
70 if (mRefreshRateChangePending) {
71 return;
72 }
73 mRefreshRateChangePending = true;
74 updateOffsets();
75 }
76
onRefreshRateChangeCompleted()77 void VSyncModulator::onRefreshRateChangeCompleted() {
78 if (!mRefreshRateChangePending) {
79 return;
80 }
81 mRefreshRateChangePending = false;
82 updateOffsets();
83 }
84
onRefreshed(bool usedRenderEngine)85 void VSyncModulator::onRefreshed(bool usedRenderEngine) {
86 bool updateOffsetsNeeded = false;
87 if (mRemainingEarlyFrameCount > 0) {
88 mRemainingEarlyFrameCount--;
89 updateOffsetsNeeded = true;
90 }
91 if (usedRenderEngine) {
92 mRemainingRenderEngineUsageCount = MIN_EARLY_GL_FRAME_COUNT_TRANSACTION;
93 updateOffsetsNeeded = true;
94 } else if (mRemainingRenderEngineUsageCount > 0) {
95 mRemainingRenderEngineUsageCount--;
96 updateOffsetsNeeded = true;
97 }
98 if (updateOffsetsNeeded) {
99 updateOffsets();
100 }
101 }
102
getOffsets()103 VSyncModulator::Offsets VSyncModulator::getOffsets() {
104 std::lock_guard<std::mutex> lock(mMutex);
105 return mOffsets;
106 }
107
getNextOffsets()108 VSyncModulator::Offsets VSyncModulator::getNextOffsets() {
109 return mOffsetMap.at(getNextOffsetType());
110 }
111
getNextOffsetType()112 VSyncModulator::OffsetType VSyncModulator::getNextOffsetType() {
113 // Early offsets are used if we're in the middle of a refresh rate
114 // change, or if we recently begin a transaction.
115 if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 ||
116 mRefreshRateChangePending) {
117 return OffsetType::Early;
118 } else if (mRemainingRenderEngineUsageCount > 0) {
119 return OffsetType::EarlyGl;
120 } else {
121 return OffsetType::Late;
122 }
123 }
124
updateOffsets()125 void VSyncModulator::updateOffsets() {
126 std::lock_guard<std::mutex> lock(mMutex);
127 updateOffsetsLocked();
128 }
129
updateOffsetsLocked()130 void VSyncModulator::updateOffsetsLocked() {
131 const Offsets desired = getNextOffsets();
132
133 if (mSfConnectionHandle != nullptr) {
134 mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf);
135 }
136
137 if (mAppConnectionHandle != nullptr) {
138 mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app);
139 }
140
141 flushOffsets();
142 }
143
flushOffsets()144 void VSyncModulator::flushOffsets() {
145 OffsetType type = getNextOffsetType();
146 mOffsets = mOffsetMap.at(type);
147 if (!mTraceDetailedInfo) {
148 return;
149 }
150 ATRACE_INT("Vsync-EarlyOffsetsOn",
151 mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Early);
152 ATRACE_INT("Vsync-EarlyGLOffsetsOn",
153 mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::EarlyGl);
154 ATRACE_INT("Vsync-LateOffsetsOn",
155 mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Late);
156 ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn",
157 mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Early);
158 ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn",
159 mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::EarlyGl);
160 ATRACE_INT("Vsync-HighFpsLateOffsetsOn",
161 mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Late);
162 }
163
164 } // namespace android
165