1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "vsync_sampler.h"
17 #include <cmath>
18 #include "vsync_generator.h"
19 #include "vsync_log.h"
20
21 namespace OHOS {
22 namespace Rosen {
23 namespace impl {
24 std::once_flag VSyncSampler::createFlag_;
25 sptr<OHOS::Rosen::VSyncSampler> VSyncSampler::instance_ = nullptr;
26
27 namespace {
28 constexpr double PI = 3.1415926;
29 constexpr int64_t g_errorThreshold = 40000000000; // 200 usec squared
30 constexpr int32_t INVAILD_TIMESTAMP = -1;
31 constexpr uint32_t MINES_SAMPLE_NUMS = 3;
32 }
GetInstance()33 sptr<OHOS::Rosen::VSyncSampler> VSyncSampler::GetInstance() noexcept
34 {
35 std::call_once(createFlag_, []() {
36 auto vsyncSampler = new VSyncSampler();
37 instance_ = vsyncSampler;
38 });
39
40 return instance_;
41 }
42
VSyncSampler()43 VSyncSampler::VSyncSampler()
44 : period_(0), phase_(0), referenceTime_(0),
45 error_(0), firstSampleIndex_(0), numSamples_(0),
46 modeUpdated_(false)
47 {
48 }
49
Reset()50 void VSyncSampler::Reset()
51 {
52 std::lock_guard<std::mutex> lock(mutex_);
53 period_ = 0;
54 phase_ = 0;
55 referenceTime_ = 0;
56 error_ = 0;
57 firstSampleIndex_ = 0;
58 numSamples_ = 0;
59 modeUpdated_ = false;
60 hardwareVSyncStatus_ = true;
61 }
62
ResetErrorLocked()63 void VSyncSampler::ResetErrorLocked()
64 {
65 presentFenceTimeOffset_ = 0;
66 error_ = 0;
67 for (uint32_t i = 0; i < NUM_PRESENT; i++) {
68 presentFenceTime_[i] = INVAILD_TIMESTAMP;
69 }
70 }
71
BeginSample()72 void VSyncSampler::BeginSample()
73 {
74 std::lock_guard<std::mutex> lock(mutex_);
75 numSamples_ = 0;
76 modeUpdated_ = false;
77 hardwareVSyncStatus_ = true;
78 }
79
SetHardwareVSyncStatus(bool enabled)80 void VSyncSampler::SetHardwareVSyncStatus(bool enabled)
81 {
82 std::lock_guard<std::mutex> lock(mutex_);
83 hardwareVSyncStatus_ = enabled;
84 }
85
GetHardwareVSyncStatus() const86 bool VSyncSampler::GetHardwareVSyncStatus() const
87 {
88 std::lock_guard<std::mutex> lock(mutex_);
89 return hardwareVSyncStatus_;
90 }
91
RegSetScreenVsyncEnabledCallback(VSyncSampler::SetScreenVsyncEnabledCallback cb)92 void VSyncSampler::RegSetScreenVsyncEnabledCallback(VSyncSampler::SetScreenVsyncEnabledCallback cb)
93 {
94 setScreenVsyncEnabledCallback_ = cb;
95 }
96
SetScreenVsyncEnabledInRSMainThread(bool enabled)97 void VSyncSampler::SetScreenVsyncEnabledInRSMainThread(bool enabled)
98 {
99 if (setScreenVsyncEnabledCallback_ == nullptr) {
100 VLOGE("SetScreenVsyncEnabled:%{public}d failed, setScreenVsyncEnabledCallback_ is null", enabled);
101 return;
102 }
103 setScreenVsyncEnabledCallback_(enabled);
104 }
105
AddSample(int64_t timeStamp)106 bool VSyncSampler::AddSample(int64_t timeStamp)
107 {
108 std::lock_guard<std::mutex> lock(mutex_);
109 if (numSamples_ == 0) {
110 phase_ = 0;
111 referenceTime_ = timeStamp;
112 CreateVSyncGenerator()->UpdateMode(period_, phase_, referenceTime_);
113 }
114
115 if (numSamples_ < MAX_SAMPLES - 1) {
116 numSamples_++;
117 } else {
118 firstSampleIndex_ = (firstSampleIndex_ + 1) % MAX_SAMPLES;
119 }
120
121 uint32_t index = (firstSampleIndex_ + numSamples_ - 1) % MAX_SAMPLES;
122 samples_[index] = timeStamp;
123
124 UpdateModeLocked();
125
126 if (numResyncSamplesSincePresent_++ > MAX_SAMPLES_WITHOUT_PRESENT) {
127 ResetErrorLocked();
128 }
129
130 // 1/2 just a empirical value
131 bool shouldDisableScreenVsync = modeUpdated_ && (error_ < g_errorThreshold / 2);
132
133 if (shouldDisableScreenVsync) {
134 // disabled screen vsync in rsMainThread
135 VLOGD("Disable Screen Vsync");
136 SetScreenVsyncEnabledInRSMainThread(false);
137 }
138
139 return !shouldDisableScreenVsync;
140 }
141
142
UpdateModeLocked()143 void VSyncSampler::UpdateModeLocked()
144 {
145 if (numSamples_ >= MIN_SAMPLES_FOR_UPDATE) {
146 int64_t sum = 0;
147 int64_t min = INT64_MAX;
148 int64_t max = 0;
149 for (uint32_t i = 1; i < numSamples_; i++) {
150 int64_t prevSample = samples_[(firstSampleIndex_ + i - 1 + MAX_SAMPLES) % MAX_SAMPLES];
151 int64_t currentSample = samples_[(firstSampleIndex_ + i) % MAX_SAMPLES];
152 int64_t diff = currentSample - prevSample;
153 min = min < diff ? min : diff;
154 max = max > diff ? max : diff;
155 sum += diff;
156 }
157 sum -= min;
158 sum -= max;
159
160 period_ = sum / (int64_t)(numSamples_ - MINES_SAMPLE_NUMS);
161
162 double scale = 2.0 * PI / period_;
163 double deltaAvgX = 0;
164 double deltaAvgY = 0;
165 for (uint32_t i = 1; i < numSamples_; i++) {
166 double delta = (samples_[(firstSampleIndex_ + i) % MAX_SAMPLES] - referenceTime_) % period_ * scale;
167 deltaAvgX += cos(delta);
168 deltaAvgY += sin(delta);
169 }
170
171 deltaAvgX /= double(numSamples_ - 1);
172 deltaAvgY /= double(numSamples_ - 1);
173
174 phase_ = int64_t(::atan2(deltaAvgY, deltaAvgX) / scale);
175
176 modeUpdated_ = true;
177 CreateVSyncGenerator()->UpdateMode(period_, phase_, referenceTime_);
178 }
179 }
180
UpdateErrorLocked()181 void VSyncSampler::UpdateErrorLocked()
182 {
183 if (!modeUpdated_) {
184 return;
185 }
186
187 int numErrSamples = 0;
188 int64_t sqErrSum = 0;
189
190 for (uint32_t i = 0; i < NUM_PRESENT; i++) {
191 int64_t t = presentFenceTime_[i];
192 if (t <= 0) {
193 continue;
194 }
195
196 int64_t sample = t - referenceTime_;
197 if (sample <= phase_) {
198 continue;
199 }
200
201 int64_t sampleErr = (sample - phase_) % period_;
202 // 1/2 just a empirical value
203 if (sampleErr > period_ / 2) {
204 sampleErr -= period_;
205 }
206 sqErrSum += sampleErr * sampleErr;
207 numErrSamples++;
208 }
209
210 if (numErrSamples > 0) {
211 error_ = sqErrSum / numErrSamples;
212 } else {
213 error_ = 0;
214 }
215 }
216
AddPresentFenceTime(int64_t timestamp)217 bool VSyncSampler::AddPresentFenceTime(int64_t timestamp)
218 {
219 std::lock_guard<std::mutex> lock(mutex_);
220 presentFenceTime_[presentFenceTimeOffset_] = timestamp;
221 presentFenceTimeOffset_ = (presentFenceTimeOffset_ + 1) % NUM_PRESENT;
222 numResyncSamplesSincePresent_ = 0;
223
224 UpdateErrorLocked();
225
226 return !modeUpdated_ || error_ > g_errorThreshold;
227 }
228
GetPeriod() const229 int64_t VSyncSampler::GetPeriod() const
230 {
231 std::lock_guard<std::mutex> lock(mutex_);
232 return period_;
233 }
234
GetPhase() const235 int64_t VSyncSampler::GetPhase() const
236 {
237 std::lock_guard<std::mutex> lock(mutex_);
238 return phase_;
239 }
240
GetRefrenceTime() const241 int64_t VSyncSampler::GetRefrenceTime() const
242 {
243 std::lock_guard<std::mutex> lock(mutex_);
244 return referenceTime_;
245 }
246
~VSyncSampler()247 VSyncSampler::~VSyncSampler()
248 {
249 }
250 } // namespace impl
251
CreateVSyncSampler()252 sptr<VSyncSampler> CreateVSyncSampler()
253 {
254 return impl::VSyncSampler::GetInstance();
255 }
256 }
257 }
258