• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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