• 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 #include <cstdint>
21 #include <mutex>
22 #include <scoped_bytrace.h>
23 #include <string>
24 #include <rs_trace.h>
25 
26 namespace OHOS {
27 namespace Rosen {
28 namespace impl {
29 std::once_flag VSyncSampler::createFlag_;
30 sptr<OHOS::Rosen::VSyncSampler> VSyncSampler::instance_ = nullptr;
31 
32 namespace {
33 constexpr double PI = 3.1415926;
34 constexpr double ERROR_THRESHOLD = 160000000000.0; // 400 usec squared
35 constexpr int32_t INVALID_TIMESTAMP = -1;
36 constexpr uint32_t MINES_SAMPLE_NUMS = 3;
37 constexpr uint32_t SAMPLES_INTERVAL_DIFF_NUMS = 2;
38 constexpr int64_t MAX_IDLE_TIME_THRESHOLD = 900000000; // 900000000ns == 900ms
39 constexpr double SAMPLE_VARIANCE_THRESHOLD = 250000000000.0; // 500 usec squared
40 constexpr int64_t INSPECTION_PERIOD = 5000000000; //5s
41 
SystemTime()42 static int64_t SystemTime()
43 {
44     timespec t = {};
45     clock_gettime(CLOCK_MONOTONIC, &t);
46     return int64_t(t.tv_sec) * 1000000000LL + t.tv_nsec; // 1000000000ns == 1s
47 }
48 }
GetInstance()49 sptr<OHOS::Rosen::VSyncSampler> VSyncSampler::GetInstance() noexcept
50 {
51     std::call_once(createFlag_, []() {
52         auto vsyncSampler = new VSyncSampler();
53         instance_ = vsyncSampler;
54     });
55 
56     return instance_;
57 }
58 
VSyncSampler()59 VSyncSampler::VSyncSampler()
60     : period_(0), phase_(0), referenceTime_(0),
61     error_(0), firstSampleIndex_(0), numSamples_(0),
62     modeUpdated_(false)
63 {
64 }
65 
ResetErrorLocked()66 void VSyncSampler::ResetErrorLocked()
67 {
68     presentFenceTimeOffset_ = 0;
69     error_ = 0;
70     for (uint32_t i = 0; i < NUM_PRESENT; i++) {
71         presentFenceTime_[i] = INVALID_TIMESTAMP;
72     }
73 }
74 
SetAdaptive(bool isAdaptive)75 void VSyncSampler::SetAdaptive(bool isAdaptive)
76 {
77     std::lock_guard<std::mutex> lock(mutex_);
78     if (isAdaptive_ == isAdaptive) {
79         return;
80     }
81     lastAdaptiveTime_ = 0;
82     isAdaptive_ = isAdaptive;
83 }
84 
SetVsyncEnabledScreenId(uint64_t vsyncEnabledScreenId)85 void VSyncSampler::SetVsyncEnabledScreenId(uint64_t vsyncEnabledScreenId)
86 {
87     RS_TRACE_NAME_FMT("SetVsyncEnabledScreenId:%lu", vsyncEnabledScreenId);
88     VLOGI("SetVsyncEnabledScreenId:" VPUBU64, vsyncEnabledScreenId);
89     std::lock_guard<std::mutex> lock(mutex_);
90     vsyncEnabledScreenId_ = vsyncEnabledScreenId;
91 }
92 
GetVsyncEnabledScreenId()93 uint64_t VSyncSampler::GetVsyncEnabledScreenId()
94 {
95     std::lock_guard<std::mutex> lock(mutex_);
96     return vsyncEnabledScreenId_;
97 }
98 
SetVsyncSamplerEnabled(bool enabled)99 void VSyncSampler::SetVsyncSamplerEnabled(bool enabled)
100 {
101     RS_TRACE_NAME_FMT("HdiOutput::SetVsyncSamplerEnabled, enableVsyncSample_:%d", enabled);
102     VLOGI("Change enableVsyncSample_, value is %{public}d", enabled);
103     enableVsyncSample_.store(enabled);
104 }
105 
GetVsyncSamplerEnabled()106 bool VSyncSampler::GetVsyncSamplerEnabled()
107 {
108     return enableVsyncSample_.load();
109 }
110 
StartSample(bool forceReSample)111 int32_t VSyncSampler::StartSample(bool forceReSample)
112 {
113     RS_TRACE_NAME_FMT("HdiOutput::StartVSyncSampler, forceReSample:%d", forceReSample);
114     if (!enableVsyncSample_.load()) {
115         RS_TRACE_NAME_FMT("disabled vsyncSample");
116         return VSYNC_ERROR_API_FAILED;
117     }
118     std::lock_guard<std::mutex> lock(mutex_);
119     if (!forceReSample && hardwareVSyncStatus_) {
120         RS_TRACE_NAME("Already Start Sample.");
121         VLOGD("Already Start Sample.");
122         return VSYNC_ERROR_OK;
123     }
124     VLOGD("Enable Screen Vsync");
125     numSamples_ = 0;
126     modeUpdated_ = false;
127     SetScreenVsyncEnabledInRSMainThreadLocked(vsyncEnabledScreenId_, true);
128     return VSYNC_ERROR_OK;
129 }
130 
ClearAllSamples()131 void VSyncSampler::ClearAllSamples()
132 {
133     ScopedBytrace func("ClearAllSamples");
134     std::lock_guard<std::mutex> lock(mutex_);
135     numSamples_ = 0;
136 }
137 
SetHardwareVSyncStatus(bool enabled)138 void VSyncSampler::SetHardwareVSyncStatus(bool enabled)
139 {
140     std::lock_guard<std::mutex> lock(mutex_);
141     hardwareVSyncStatus_ = enabled;
142 }
143 
RecordDisplayVSyncStatus(bool enabled)144 void VSyncSampler::RecordDisplayVSyncStatus(bool enabled)
145 {
146     std::lock_guard<std::mutex> lock(mutex_);
147     displayVSyncStatus_ = enabled;
148 }
149 
RollbackHardwareVSyncStatus()150 void VSyncSampler::RollbackHardwareVSyncStatus()
151 {
152     std::lock_guard<std::mutex> lock(mutex_);
153     hardwareVSyncStatus_ = displayVSyncStatus_;
154 }
155 
RegSetScreenVsyncEnabledCallback(VSyncSampler::SetScreenVsyncEnabledCallback cb)156 void VSyncSampler::RegSetScreenVsyncEnabledCallback(VSyncSampler::SetScreenVsyncEnabledCallback cb)
157 {
158     std::lock_guard<std::mutex> lock(mutex_);
159     setScreenVsyncEnabledCallback_ = cb;
160 }
161 
SetScreenVsyncEnabledInRSMainThread(uint64_t screenId,bool enabled)162 void VSyncSampler::SetScreenVsyncEnabledInRSMainThread(uint64_t screenId, bool enabled)
163 {
164     std::lock_guard<std::mutex> lock(mutex_);
165     SetScreenVsyncEnabledInRSMainThreadLocked(screenId, enabled);
166 }
167 
SetScreenVsyncEnabledInRSMainThreadLocked(uint64_t screenId,bool enabled)168 void VSyncSampler::SetScreenVsyncEnabledInRSMainThreadLocked(uint64_t screenId, bool enabled)
169 {
170     if (setScreenVsyncEnabledCallback_ == nullptr) {
171         VLOGE("SetScreenVsyncEnabled:%{public}d failed, cb is null", enabled);
172         return;
173     }
174     hardwareVSyncStatus_ = enabled;
175     setScreenVsyncEnabledCallback_(screenId, enabled);
176 }
177 
AddSample(int64_t timeStamp)178 bool VSyncSampler::AddSample(int64_t timeStamp)
179 {
180     if (timeStamp < 0) {
181         return true;
182     }
183     std::lock_guard<std::mutex> lock(mutex_);
184     if (!hardwareVSyncStatus_) {
185         return true;
186     }
187     if (numSamples_ > 0) {
188         auto preSample = samples_[(firstSampleIndex_ + numSamples_ - 1) % MAX_SAMPLES];
189 
190         if (auto intervalStamp = timeStamp - preSample; intervalStamp <= 0) {
191             RS_TRACE_NAME_FMT("VSyncSampler::AddSample, invalid sample, preSample is larger");
192             numSamples_ = 0;
193             return true;
194         }
195     }
196 
197     if (isAdaptive_ && SystemTime() - lastAdaptiveTime_ < INSPECTION_PERIOD) {
198         return true;
199     }
200 
201     if (numSamples_ < MAX_SAMPLES - 1) {
202         numSamples_++;
203     } else {
204         firstSampleIndex_ = (firstSampleIndex_ + 1) % MAX_SAMPLES;
205     }
206 
207     if (firstSampleIndex_ + numSamples_ >= 1) {
208         uint32_t index = (firstSampleIndex_ + numSamples_ - 1) % MAX_SAMPLES;
209         samples_[index] = timeStamp;
210     }
211 
212     UpdateReferenceTimeLocked();
213     UpdateModeLocked();
214 
215     if (numResyncSamplesSincePresent_++ > MAX_SAMPLES_WITHOUT_PRESENT) {
216         ResetErrorLocked();
217     }
218 
219     // 1/2 just a empirical value
220     bool shouldDisableScreenVsync = modeUpdated_ && (error_ < ERROR_THRESHOLD / 2);
221     if (shouldDisableScreenVsync) {
222         // disabled screen vsync in rsMainThread
223         VLOGD("Disable Screen Vsync");
224         SetScreenVsyncEnabledInRSMainThreadLocked(vsyncEnabledScreenId_, false);
225     }
226 
227     return !shouldDisableScreenVsync;
228 }
229 
UpdateReferenceTimeLocked()230 void VSyncSampler::UpdateReferenceTimeLocked()
231 {
232     bool isFrameRateChanging = CreateVSyncGenerator()->GetFrameRateChaingStatus();
233     // update referenceTime at the first sample, unless in adaptive sync mode
234     if (!isFrameRateChanging && (numSamples_ == 1) && !isAdaptive_) {
235         phase_ = 0;
236         referenceTime_ = samples_[firstSampleIndex_];
237         CheckIfFirstRefreshAfterIdleLocked();
238         CreateVSyncGenerator()->UpdateMode(0, phase_, referenceTime_);
239     } else if (isFrameRateChanging && (numSamples_ >= 2)) { // at least 2 samples
240         int64_t prevSample = samples_[(firstSampleIndex_ + numSamples_ - 2) % MAX_SAMPLES]; // at least 2 samples
241         int64_t latestSample = samples_[(firstSampleIndex_ + numSamples_ - 1) % MAX_SAMPLES];
242         CheckIfFirstRefreshAfterIdleLocked();
243         CreateVSyncGenerator()->CheckAndUpdateReferenceTime(latestSample - prevSample, prevSample);
244     }
245 }
246 
UpdateModeLocked()247 void VSyncSampler::UpdateModeLocked()
248 {
249     if (!CreateVSyncGenerator()->GetFrameRateChaingStatus() && (numSamples_ >= MIN_SAMPLES_FOR_UPDATE)) {
250         int64_t sum = 0;
251         int64_t min = INT64_MAX;
252         int64_t max = 0;
253         int64_t diffPrev = 0;
254         int64_t diff = 0;
255         double variance = 0;
256         for (uint32_t i = 1; i < numSamples_; i++) {
257             int64_t prevSample = samples_[(firstSampleIndex_ + i - 1 + MAX_SAMPLES) % MAX_SAMPLES];
258             int64_t currentSample = samples_[(firstSampleIndex_ + i) % MAX_SAMPLES];
259             diffPrev = diff;
260             diff = currentSample - prevSample;
261             if (diffPrev != 0) {
262                 int64_t delta = diff - diffPrev;
263                 variance += pow(static_cast<double>(delta), 2); // the 2nd power of delta
264             }
265             min = min < diff ? min : diff;
266             max = max > diff ? max : diff;
267             sum += diff;
268         }
269         variance /= (numSamples_ - SAMPLES_INTERVAL_DIFF_NUMS);
270         if (variance > SAMPLE_VARIANCE_THRESHOLD) {
271             // keep only the latest 5 samples, and sample the next timestamp.
272             firstSampleIndex_ = (firstSampleIndex_ + numSamples_ - MIN_SAMPLES_FOR_UPDATE + 1) % MAX_SAMPLES;
273             numSamples_ = MIN_SAMPLES_FOR_UPDATE - 1;
274             referenceTime_ = samples_[firstSampleIndex_];
275             return;
276         }
277 
278         sum -= min;
279         sum -= max;
280 
281         period_ = sum / (int64_t)(numSamples_ - MINES_SAMPLE_NUMS);
282         if (period_ <= 0) {
283             return;
284         }
285 
286         referenceTime_ = samples_[firstSampleIndex_];
287 
288         ComputePhaseLocked();
289 
290         modeUpdated_ = true;
291         CheckIfFirstRefreshAfterIdleLocked();
292         CreateVSyncGenerator()->UpdateMode(period_, phase_, referenceTime_);
293         pendingPeriod_ = period_;
294     }
295 }
296 
UpdateErrorLocked()297 void VSyncSampler::UpdateErrorLocked()
298 {
299     if (!modeUpdated_ || (period_ <= 0)) {
300         return;
301     }
302 
303     int numErrSamples = 0;
304     double sqErrSum = 0;
305 
306     for (uint32_t i = 0; i < NUM_PRESENT; i++) {
307         int64_t t = presentFenceTime_[i];
308         if (t <= 0) {
309             continue;
310         }
311 
312         int64_t sample = t - referenceTime_;
313         if (sample <= phase_) {
314             continue;
315         }
316 
317         int64_t sampleErr = (sample - phase_) % period_;
318         // 1/2 just a empirical value
319         if (sampleErr > period_ / 2) {
320             sampleErr -= period_;
321         }
322         sqErrSum += pow(static_cast<double>(sampleErr), 2); // the 2nd power of sampleErr
323         numErrSamples++;
324     }
325 
326     if (numErrSamples > 0) {
327         error_ = sqErrSum / numErrSamples;
328     } else {
329         error_ = 0;
330     }
331 }
332 
AddPresentFenceTime(uint32_t screenId,int64_t timestamp)333 bool VSyncSampler::AddPresentFenceTime(uint32_t screenId, int64_t timestamp)
334 {
335     if (timestamp < 0) {
336         return false;
337     }
338     std::lock_guard<std::mutex> lock(mutex_);
339     if (isAdaptive_) {
340         auto prePresentFenceTime = presentFenceTime_[(presentFenceTimeOffset_ + NUM_PRESENT - 1) % NUM_PRESENT];
341         auto interval = timestamp - prePresentFenceTime;
342         if (CreateVSyncGenerator()->CheckSampleIsAdaptive(interval)) {
343             RS_TRACE_NAME_FMT("VSyncSampler::AddPresentFenceTime, adaptive sample");
344             lastAdaptiveTime_ = SystemTime();
345         }
346     }
347     if (screenId != vsyncEnabledScreenId_) {
348         return false;
349     }
350     presentFenceTime_[presentFenceTimeOffset_] = timestamp;
351 
352     presentFenceTimeOffset_ = (presentFenceTimeOffset_ + 1) % NUM_PRESENT;
353     numResyncSamplesSincePresent_ = 0;
354 
355     UpdateErrorLocked();
356     if (error_ > ERROR_THRESHOLD) {
357         RS_TRACE_NAME_FMT("PresentFenceTime error_:%lf", error_);
358     }
359 
360     return !modeUpdated_ || error_ > ERROR_THRESHOLD;
361 }
362 
CheckIfFirstRefreshAfterIdleLocked()363 void VSyncSampler::CheckIfFirstRefreshAfterIdleLocked()
364 {
365     if (presentFenceTimeOffset_ + NUM_PRESENT < 1) {
366         return;
367     }
368     int64_t curFenceTimeStamp = presentFenceTime_[presentFenceTimeOffset_];
369     int64_t prevFenceTimeStamp = presentFenceTime_[(presentFenceTimeOffset_ + NUM_PRESENT - 1) % NUM_PRESENT];
370     if ((curFenceTimeStamp != INVALID_TIMESTAMP) && (prevFenceTimeStamp != INVALID_TIMESTAMP) &&
371         (curFenceTimeStamp - prevFenceTimeStamp > MAX_IDLE_TIME_THRESHOLD)) {
372         CreateVSyncGenerator()->StartRefresh();
373     }
374 }
375 
ComputePhaseLocked()376 void VSyncSampler::ComputePhaseLocked()
377 {
378     double scale = 2.0 * PI / period_;
379     double deltaAvgX = 0;
380     double deltaAvgY = 0;
381     for (uint32_t i = 1; i < numSamples_; i++) {
382         double delta = (samples_[(firstSampleIndex_ + i) % MAX_SAMPLES] - referenceTime_) % period_ * scale;
383         deltaAvgX += cos(delta);
384         deltaAvgY += sin(delta);
385     }
386 
387     deltaAvgX /= double(numSamples_ - 1);
388     deltaAvgY /= double(numSamples_ - 1);
389 
390     phase_ = int64_t(::atan2(deltaAvgY, deltaAvgX) / scale);
391 }
392 
GetPeriod() const393 int64_t VSyncSampler::GetPeriod() const
394 {
395     std::lock_guard<std::mutex> lock(mutex_);
396     return period_;
397 }
398 
GetPhase() const399 int64_t VSyncSampler::GetPhase() const
400 {
401     std::lock_guard<std::mutex> lock(mutex_);
402     return phase_;
403 }
404 
GetRefrenceTime() const405 int64_t VSyncSampler::GetRefrenceTime() const
406 {
407     std::lock_guard<std::mutex> lock(mutex_);
408     return referenceTime_;
409 }
410 
GetHardwarePeriod() const411 int64_t VSyncSampler::GetHardwarePeriod() const
412 {
413     std::lock_guard<std::mutex> lock(mutex_);
414     int64_t period = period_;
415     if (!modeUpdated_ && pendingPeriod_ != 0) {
416         period = pendingPeriod_;
417     }
418     return period;
419 }
420 
SetPendingPeriod(int64_t period)421 void VSyncSampler::SetPendingPeriod(int64_t period)
422 {
423     if (period <= 0) {
424         return;
425     }
426     std::lock_guard<std::mutex> lock(mutex_);
427     pendingPeriod_ = period;
428     CreateVSyncGenerator()->SetFrameRateChangingStatus(true);
429 }
430 
Dump(std::string & result)431 void VSyncSampler::Dump(std::string &result)
432 {
433     std::lock_guard<std::mutex> lock(mutex_);
434     result.append("\n-- VSyncSampler --");
435     result += "\nperiod:" + std::to_string(period_);
436     result += "\nphase:" + std::to_string(phase_);
437     result += "\nreferenceTime:" + std::to_string(referenceTime_);
438     result += "\nmodeUpdated:" + std::to_string(modeUpdated_);
439     result += "\nhardwareVSyncStatus:" + std::to_string(hardwareVSyncStatus_);
440     result += "\nnumSamples:" + std::to_string(numSamples_);
441     result += "\nsamples:[";
442     for (uint32_t i = 0; i < numSamples_; i++) {
443         result += std::to_string(samples_[(firstSampleIndex_ + i) % MAX_SAMPLES]) + ",";
444     }
445     result += "]";
446     result += "\npresentFenceTime:[";
447     for (uint32_t i = 0; i < NUM_PRESENT; i++) {
448         result += std::to_string(presentFenceTime_[i]) + ",";
449     }
450     result += "]";
451     result += "\npresentFenceTimeOffset:" + std::to_string(presentFenceTimeOffset_);
452     result += "\nvsyncEnabledScreenId:" + std::to_string(vsyncEnabledScreenId_);
453 }
454 
~VSyncSampler()455 VSyncSampler::~VSyncSampler()
456 {
457 }
458 } // namespace impl
459 
CreateVSyncSampler()460 sptr<VSyncSampler> CreateVSyncSampler()
461 {
462     return impl::VSyncSampler::GetInstance();
463 }
464 }
465 }