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