• 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_generator.h"
17 #include <scoped_bytrace.h>
18 #include <sched.h>
19 #include <sys/resource.h>
20 #include <string>
21 
22 namespace OHOS {
23 namespace Rosen {
24 namespace impl {
25 namespace {
GetSysTimeNs()26 static int64_t GetSysTimeNs()
27 {
28     auto now = std::chrono::steady_clock::now().time_since_epoch();
29     return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
30 }
31 
32 // 1.5ms
33 constexpr int64_t maxWaleupDelay = 1500000;
34 constexpr int32_t THREAD_PRIORTY = -6;
35 constexpr int32_t SCHED_PRIORITY = 2;
36 constexpr int64_t errorThreshold = 500000;
37 
SetThreadHighPriority()38 static void SetThreadHighPriority()
39 {
40     setpriority(PRIO_PROCESS, 0, THREAD_PRIORTY);
41     struct sched_param param = {0};
42     param.sched_priority = SCHED_PRIORITY;
43     sched_setscheduler(0, SCHED_FIFO, &param);
44 }
45 }
46 
47 std::once_flag VSyncGenerator::createFlag_;
48 sptr<OHOS::Rosen::VSyncGenerator> VSyncGenerator::instance_ = nullptr;
49 
GetInstance()50 sptr<OHOS::Rosen::VSyncGenerator> VSyncGenerator::GetInstance() noexcept
51 {
52     std::call_once(createFlag_, []() {
53         auto vsyncGenerator = new VSyncGenerator();
54         instance_ = vsyncGenerator;
55     });
56 
57     return instance_;
58 }
59 
DeleteInstance()60 void VSyncGenerator::DeleteInstance() noexcept
61 {
62     instance_ = nullptr;
63 }
64 
VSyncGenerator()65 VSyncGenerator::VSyncGenerator()
66     : period_(0), phase_(0), refrenceTime_(0), wakeupDelay_(0)
67 {
68     vsyncThreadRunning_ = true;
69     thread_ = std::thread(std::bind(&VSyncGenerator::ThreadLoop, this));
70     pthread_setname_np(thread_.native_handle(), "VSyncGenerator");
71 }
72 
~VSyncGenerator()73 VSyncGenerator::~VSyncGenerator()
74 {
75     {
76         std::unique_lock<std::mutex> locker(mutex_);
77         vsyncThreadRunning_ = false;
78     }
79     if (thread_.joinable()) {
80         con_.notify_all();
81         thread_.join();
82     }
83 }
84 
ThreadLoop()85 void VSyncGenerator::ThreadLoop()
86 {
87     // set thread priorty
88     SetThreadHighPriority();
89 
90     int64_t occurTimestamp = 0;
91     int64_t nextTimeStamp = 0;
92     int64_t occurRefrenceTime = 0;
93     while (vsyncThreadRunning_ == true) {
94         std::vector<Listener> listeners;
95         {
96             std::unique_lock<std::mutex> locker(mutex_);
97             occurRefrenceTime = refrenceTime_;
98             if (period_ == 0) {
99                 if (vsyncThreadRunning_ == true) {
100                     con_.wait(locker);
101                 }
102                 continue;
103             }
104             occurTimestamp = GetSysTimeNs();
105             nextTimeStamp = ComputeNextVSyncTimeStamp(occurTimestamp, occurRefrenceTime);
106             if (nextTimeStamp == INT64_MAX) {
107                 if (vsyncThreadRunning_ == true) {
108                     con_.wait(locker);
109                 }
110                 continue;
111             }
112         }
113 
114         bool isWakeup = false;
115         if (occurTimestamp < nextTimeStamp) {
116             std::unique_lock<std::mutex> lck(waitForTimeoutMtx_);
117             auto err = waitForTimeoutCon_.wait_for(lck, std::chrono::nanoseconds(nextTimeStamp - occurTimestamp));
118             if (err == std::cv_status::timeout) {
119                 isWakeup = true;
120             } else {
121                 ScopedBytrace func("VSyncGenerator::ThreadLoop::Continue");
122                 continue;
123             }
124         }
125         {
126             std::unique_lock<std::mutex> locker(mutex_);
127             occurTimestamp = GetSysTimeNs();
128             if (isWakeup) {
129                 UpdateWakeupDelay(occurTimestamp, nextTimeStamp);
130             }
131             listeners = GetListenerTimeouted(occurTimestamp, occurRefrenceTime);
132         }
133         ScopedBytrace func(
134             "GenerateVsyncCount:" + std::to_string(listeners.size()) + ", period:" + std::to_string(period_));
135         for (uint32_t i = 0; i < listeners.size(); i++) {
136             listeners[i].callback_->OnVSyncEvent(listeners[i].lastTime_, period_);
137         }
138     }
139 }
140 
UpdateWakeupDelay(int64_t occurTimestamp,int64_t nextTimeStamp)141 void VSyncGenerator::UpdateWakeupDelay(int64_t occurTimestamp, int64_t nextTimeStamp)
142 {
143     // 63, 1 / 64
144     wakeupDelay_ = ((wakeupDelay_ * 63) + (occurTimestamp - nextTimeStamp)) / 64;
145     wakeupDelay_ = wakeupDelay_ > maxWaleupDelay ? maxWaleupDelay : wakeupDelay_;
146 }
147 
ComputeNextVSyncTimeStamp(int64_t now,int64_t refrenceTime)148 int64_t VSyncGenerator::ComputeNextVSyncTimeStamp(int64_t now, int64_t refrenceTime)
149 {
150     int64_t nextVSyncTime = INT64_MAX;
151     for (uint32_t i = 0; i < listeners_.size(); i++) {
152         int64_t t = ComputeListenerNextVSyncTimeStamp(listeners_[i], now, refrenceTime);
153         if (t < nextVSyncTime) {
154             nextVSyncTime = t;
155         }
156     }
157 
158     return nextVSyncTime;
159 }
160 
ComputeListenerNextVSyncTimeStamp(const Listener & listener,int64_t now,int64_t refrenceTime)161 int64_t VSyncGenerator::ComputeListenerNextVSyncTimeStamp(const Listener& listener, int64_t now, int64_t refrenceTime)
162 {
163     int64_t lastVSyncTime = listener.lastTime_ + wakeupDelay_;
164     if (now < lastVSyncTime) {
165         now = lastVSyncTime;
166     }
167 
168     now -= refrenceTime;
169     int64_t phase = phase_ + listener.phase_;
170     now -= phase;
171     if (now < 0) {
172         now = -period_;
173     }
174     int64_t numPeriod = now / period_;
175     int64_t nextTime = (numPeriod + 1) * period_ + phase;
176     nextTime += refrenceTime;
177 
178     // 3 / 5 just empirical value
179     if (nextTime - listener.lastTime_ < (3 * period_ / 5)) {
180         nextTime += period_;
181     }
182 
183     nextTime -= wakeupDelay_;
184     return nextTime;
185 }
186 
GetListenerTimeouted(int64_t now,int64_t refrenceTime)187 std::vector<VSyncGenerator::Listener> VSyncGenerator::GetListenerTimeouted(int64_t now, int64_t refrenceTime)
188 {
189     std::vector<VSyncGenerator::Listener> ret;
190     int64_t onePeriodAgo = now - period_;
191 
192     for (uint32_t i = 0; i < listeners_.size(); i++) {
193         int64_t t = ComputeListenerNextVSyncTimeStamp(listeners_[i], onePeriodAgo, refrenceTime);
194         if (t < now || (t - now < errorThreshold)) {
195             listeners_[i].lastTime_ = t;
196             ret.push_back(listeners_[i]);
197         }
198     }
199     return ret;
200 }
201 
UpdateMode(int64_t period,int64_t phase,int64_t refrenceTime)202 VsyncError VSyncGenerator::UpdateMode(int64_t period, int64_t phase, int64_t refrenceTime)
203 {
204     std::lock_guard<std::mutex> locker(mutex_);
205     if (period < 0 || refrenceTime < 0) {
206         return VSYNC_ERROR_INVALID_ARGUMENTS;
207     }
208     period_ = period;
209     phase_ = phase;
210     refrenceTime_ = refrenceTime;
211     con_.notify_all();
212     return VSYNC_ERROR_OK;
213 }
214 
AddListener(int64_t phase,const sptr<OHOS::Rosen::VSyncGenerator::Callback> & cb)215 VsyncError VSyncGenerator::AddListener(int64_t phase, const sptr<OHOS::Rosen::VSyncGenerator::Callback>& cb)
216 {
217     std::lock_guard<std::mutex> locker(mutex_);
218     if (cb == nullptr) {
219         return VSYNC_ERROR_INVALID_ARGUMENTS;
220     }
221     Listener listener;
222     listener.phase_ = phase;
223     listener.callback_ = cb;
224     // just correct period / 2 time
225     listener.lastTime_ = GetSysTimeNs() - period_ / 2 + phase_;
226 
227     listeners_.push_back(listener);
228     con_.notify_all();
229     return VSYNC_ERROR_OK;
230 }
231 
RemoveListener(const sptr<OHOS::Rosen::VSyncGenerator::Callback> & cb)232 VsyncError VSyncGenerator::RemoveListener(const sptr<OHOS::Rosen::VSyncGenerator::Callback>& cb)
233 {
234     std::lock_guard<std::mutex> locker(mutex_);
235     if (cb == nullptr) {
236         return VSYNC_ERROR_INVALID_ARGUMENTS;
237     }
238     bool removeFlag = false;
239     auto it = listeners_.begin();
240     for (; it < listeners_.end(); it++) {
241         if (it->callback_ == cb) {
242             listeners_.erase(it);
243             removeFlag = true;
244             break;
245         }
246     }
247     if (!removeFlag) {
248         return VSYNC_ERROR_INVALID_ARGUMENTS;
249     }
250     con_.notify_all();
251     return VSYNC_ERROR_OK;
252 }
253 
ChangePhaseOffset(const sptr<OHOS::Rosen::VSyncGenerator::Callback> & cb,int64_t offset)254 VsyncError VSyncGenerator::ChangePhaseOffset(const sptr<OHOS::Rosen::VSyncGenerator::Callback>& cb, int64_t offset)
255 {
256     std::lock_guard<std::mutex> locker(mutex_);
257     if (cb == nullptr) {
258         return VSYNC_ERROR_INVALID_ARGUMENTS;
259     }
260     auto it = listeners_.begin();
261     for (; it < listeners_.end(); it++) {
262         if (it->callback_ == cb) {
263             break;
264         }
265     }
266     if (it != listeners_.end()) {
267         it->phase_ = offset;
268     } else {
269         return VSYNC_ERROR_INVALID_OPERATING;
270     }
271     return VSYNC_ERROR_OK;
272 }
273 
IsEnable()274 bool VSyncGenerator::IsEnable()
275 {
276     std::lock_guard<std::mutex> locker(mutex_);
277     return period_ > 0;
278 }
279 } // namespace impl
CreateVSyncGenerator()280 sptr<VSyncGenerator> CreateVSyncGenerator()
281 {
282     return impl::VSyncGenerator::GetInstance();
283 }
284 
DestroyVSyncGenerator()285 void DestroyVSyncGenerator()
286 {
287     impl::VSyncGenerator::DeleteInstance();
288 }
289 }
290 }
291