1 /*
2 * Copyright (c) 2023 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 #include "core/pipeline/pipeline_base.h"
16 #include "core/components_ng/manager/display_sync/ui_display_sync.h"
17 #ifdef ENABLE_ROSEN_BACKEND
18 #include "transaction/rs_interfaces.h"
19 #endif
20
21 namespace OHOS::Ace {
CheckRate(int32_t vsyncRate,int32_t refreshRateMode)22 void UIDisplaySync::CheckRate(int32_t vsyncRate, int32_t refreshRateMode)
23 {
24 SetVsyncRate(vsyncRate);
25 SetRefreshRateMode(refreshRateMode);
26
27 CHECK_NULL_VOID(data_);
28 CHECK_NULL_VOID(data_->rate_);
29 CHECK_NULL_VOID(data_->rateRange_);
30 drawFPS_ = FindMatchedRefreshRate(vsyncRate, data_->rateRange_->preferred_);
31 if (drawFPS_ < data_->rateRange_->min_ ||
32 drawFPS_ > data_->rateRange_->max_) {
33 drawFPS_ = SearchMatchedRate(vsyncRate);
34 }
35
36 if (drawFPS_ == 0) {
37 return;
38 }
39
40 int32_t curRate = vsyncRate / drawFPS_;
41 if (data_->rate_ != curRate) {
42 data_->rate_ = curRate;
43 rateChanged_ = true;
44 ACE_SCOPED_TRACE("[%s] Id[%" PRIu64 "] RateChangedTo: %d", __func__, GetId(), data_->rate_);
45 }
46 return;
47 }
48
UpdateData(int64_t nanoTimestamp,int32_t vsyncPeriod)49 void UIDisplaySync::UpdateData(int64_t nanoTimestamp, int32_t vsyncPeriod)
50 {
51 SetTimestampData(nanoTimestamp);
52 int64_t targetTimestamp = nanoTimestamp + static_cast<int64_t>(vsyncPeriod * data_->rate_);
53 SetTargetTimestampData(targetTimestamp);
54 }
55
JudgeWhetherSkip()56 void UIDisplaySync::JudgeWhetherSkip()
57 {
58 if (rateChanged_) {
59 data_->count_ = 0;
60 rateChanged_ = false;
61 }
62
63 if (data_->count_ == 0) {
64 data_->noSkip_ = true;
65 } else {
66 data_->noSkip_ = false;
67 }
68
69 if (data_->rate_ && (data_->rate_ - data_->count_) == 1) {
70 data_->count_ = -1;
71 }
72 data_->count_++;
73 }
74
OnFrame()75 void UIDisplaySync::OnFrame()
76 {
77 ACE_SCOPED_TRACE("DisplaySyncId[%" PRIu64 "] Type[%d] Timestamp[%" PRIu64 "] TargetTimestamp[%" PRIu64 "]"
78 "FrameRateRange[%d, %d, %d] DrawFPS[%d] VSyncRate[%d] Rate[%d] noSkip[%d]",
79 GetId(), static_cast<int32_t>(uiObjectType_), data_->timestamp_, data_->targetTimestamp_,
80 data_->rateRange_->min_, data_->rateRange_->max_, data_->rateRange_->preferred_,
81 drawFPS_, sourceVsyncRate_, data_->rate_, data_->noSkip_);
82 TAG_LOGD(AceLogTag::ACE_DISPLAY_SYNC, "Id[%{public}" PRIu64 "] Type[%{public}d] FrameRateRange[%{public}d, "
83 "%{public}d, %{public}d], DrawFPS[%{public}d] VSyncRate[%{public}d] Rate[%{public}d] noSkip[%{public}d]",
84 GetId(), static_cast<int32_t>(uiObjectType_), data_->rateRange_->min_, data_->rateRange_->max_,
85 data_->rateRange_->preferred_, drawFPS_, sourceVsyncRate_, data_->rate_, data_->noSkip_);
86 if (data_->noSkip_ && data_->onFrame_) {
87 data_->onFrame_();
88 }
89
90 // Callback from JS_DisplaySync and Native_XComponent
91 if (data_->noSkip_ && data_->onFrameWithData_) {
92 data_->onFrameWithData_(data_);
93 }
94
95 // Callback from Animator
96 if (data_->noSkip_ && data_->onFrameWithTimestamp_) {
97 data_->onFrameWithTimestamp_(data_->timestamp_);
98 }
99
100 JudgeWhetherRequestFrame();
101 }
102
AddToPipeline(WeakPtr<PipelineBase> & pipelineContext)103 void UIDisplaySync::AddToPipeline(WeakPtr<PipelineBase>& pipelineContext)
104 {
105 if (GetCurrentContext()) {
106 TAG_LOGD(AceLogTag::ACE_DISPLAY_SYNC, "[DisplaySync] existed in Pipeline.");
107 return;
108 }
109
110 auto context = pipelineContext.Upgrade();
111 if (!context) {
112 context = PipelineBase::GetCurrentContextSafelyWithCheck();
113 if (!context) {
114 TAG_LOGE(AceLogTag::ACE_DISPLAY_SYNC, "[DisplaySync] AddToPipeline CurrentContext is nullptr.");
115 return;
116 }
117 TAG_LOGD(AceLogTag::ACE_DISPLAY_SYNC, "[DisplaySync] Add to current context safely.");
118 }
119
120 context_ = context;
121 RefPtr<UIDisplaySyncManager> dsm = context->GetOrCreateUIDisplaySyncManager();
122 if (!dsm) {
123 return;
124 }
125 dsm->AddDisplaySync(AceType::Claim(this));
126 }
127
DelFromPipeline(WeakPtr<PipelineBase> & pipelineContext)128 void UIDisplaySync::DelFromPipeline(WeakPtr<PipelineBase>& pipelineContext)
129 {
130 auto context = GetCurrentContext();
131 if (!context) {
132 TAG_LOGE(AceLogTag::ACE_DISPLAY_SYNC, "[DisplaySync] DelFromPipeline CurrentContext is nullptr.");
133 return;
134 }
135
136 RefPtr<UIDisplaySyncManager> dsm = context->GetOrCreateUIDisplaySyncManager();
137 if (!dsm) {
138 TAG_LOGE(AceLogTag::ACE_DISPLAY_SYNC, "[DisplaySync] DSM is nullptr.");
139 return;
140 }
141 dsm->RemoveDisplaySync(AceType::Claim(this));
142 context_ = nullptr;
143 }
144
IsAddToPipeline(WeakPtr<PipelineBase> & pipelineContext)145 bool UIDisplaySync::IsAddToPipeline(WeakPtr<PipelineBase>& pipelineContext)
146 {
147 auto context = GetCurrentContext();
148 if (!context) {
149 return false;
150 }
151
152 RefPtr<UIDisplaySyncManager> dsm = context->GetOrCreateUIDisplaySyncManager();
153 if (!dsm) {
154 return false;
155 }
156 return dsm->HasDisplaySync(AceType::Claim(this));
157 }
158
AddToPipelineOnContainer()159 void UIDisplaySync::AddToPipelineOnContainer()
160 {
161 WeakPtr<PipelineBase> pipeline = PipelineBase::GetCurrentContext();
162 AddToPipeline(pipeline);
163 return;
164 }
165
DelFromPipelineOnContainer()166 void UIDisplaySync::DelFromPipelineOnContainer()
167 {
168 WeakPtr<PipelineBase> pipeline = PipelineBase::GetCurrentContext();
169 DelFromPipeline(pipeline);
170 return;
171 }
172
IsOnPipeline()173 bool UIDisplaySync::IsOnPipeline()
174 {
175 WeakPtr<PipelineBase> pipeline = PipelineBase::GetCurrentContext();
176 return IsAddToPipeline(pipeline);
177 }
178
RequestFrame()179 void UIDisplaySync::RequestFrame()
180 {
181 auto context = GetCurrentContext();
182 if (!context) {
183 return;
184 }
185 context->RequestFrame();
186 }
187
JudgeWhetherRequestFrame()188 void UIDisplaySync::JudgeWhetherRequestFrame()
189 {
190 bool isNeedRequest = data_->onFrame_ || data_->onFrameWithData_ || data_->onFrameWithTimestamp_;
191 if (isNeedRequest) {
192 RequestFrame();
193 }
194 }
195
RegisterOnFrame(OnFrameCallBack && onFrameCallBack)196 void UIDisplaySync::RegisterOnFrame(OnFrameCallBack&& onFrameCallBack)
197 {
198 data_->onFrame_ = std::move(onFrameCallBack);
199 }
200
RegisterOnFrameWithData(OnFrameCallBackWithData && onFrameCallBack)201 void UIDisplaySync::RegisterOnFrameWithData(OnFrameCallBackWithData&& onFrameCallBack)
202 {
203 data_->onFrameWithData_ = std::move(onFrameCallBack);
204 }
205
RegisterOnFrameWithTimestamp(OnFrameCallBackWithTimestamp && onFrameCallBack)206 void UIDisplaySync::RegisterOnFrameWithTimestamp(OnFrameCallBackWithTimestamp&& onFrameCallBack)
207 {
208 data_->onFrameWithTimestamp_ = std::move(onFrameCallBack);
209 }
210
UnregisterOnFrame()211 void UIDisplaySync::UnregisterOnFrame()
212 {
213 data_->onFrame_ = nullptr;
214 data_->onFrameWithData_ = nullptr;
215 data_->onFrameWithTimestamp_ = nullptr;
216 }
217
SetTimestampData(int64_t timestamp)218 void UIDisplaySync::SetTimestampData(int64_t timestamp)
219 {
220 data_->SetTimestamp(timestamp);
221 }
222
GetTimestampData() const223 int64_t UIDisplaySync::GetTimestampData() const
224 {
225 return data_->GetTimestamp();
226 }
227
SetTargetTimestampData(int64_t targetTimestamp)228 void UIDisplaySync::SetTargetTimestampData(int64_t targetTimestamp)
229 {
230 data_->SetTargetTimestamp(targetTimestamp);
231 }
232
GetTargetTimestampData() const233 int64_t UIDisplaySync::GetTargetTimestampData() const
234 {
235 return data_->GetTargetTimestamp();
236 }
237
SetRefreshRateMode(int32_t refreshRateMode)238 void UIDisplaySync::SetRefreshRateMode(int32_t refreshRateMode)
239 {
240 refreshRateMode_ = refreshRateMode;
241 }
242
GetRefreshRateMode() const243 int32_t UIDisplaySync::GetRefreshRateMode() const
244 {
245 return refreshRateMode_;
246 }
247
IsAutoRefreshRateMode() const248 bool UIDisplaySync::IsAutoRefreshRateMode() const
249 {
250 return refreshRateMode_ == static_cast<int32_t>(RefreshRateMode::REFRESHRATE_MODE_AUTO);
251 }
252
IsNonAutoRefreshRateMode() const253 bool UIDisplaySync::IsNonAutoRefreshRateMode() const
254 {
255 return refreshRateMode_ != static_cast<int32_t>(RefreshRateMode::REFRESHRATE_MODE_AUTO);
256 }
257
FindRefreshRateFactors(int32_t refreshRate)258 std::vector<int32_t> UIDisplaySync::FindRefreshRateFactors(int32_t refreshRate)
259 {
260 std::vector<int32_t> refreshRateFactors;
261 for (int32_t i = 1; i * i <= refreshRate; ++i) {
262 if (refreshRate % i == 0) {
263 refreshRateFactors.emplace_back(i);
264 if (i != refreshRate / i) {
265 refreshRateFactors.emplace_back(refreshRate / i);
266 }
267 }
268 }
269 sort(refreshRateFactors.begin(), refreshRateFactors.end());
270 return refreshRateFactors;
271 }
272
FindMatchedRefreshRate(int32_t vsyncRate,int32_t targetRate)273 int32_t UIDisplaySync::FindMatchedRefreshRate(int32_t vsyncRate, int32_t targetRate)
274 {
275 if (targetRate == 0 || targetRate > vsyncRate) {
276 return vsyncRate;
277 }
278
279 if (IsCommonDivisor(targetRate, vsyncRate)) {
280 return targetRate;
281 }
282
283 if (!refreshRateToFactorsMap_.count(vsyncRate)) {
284 refreshRateToFactorsMap_[vsyncRate] = FindRefreshRateFactors(vsyncRate);
285 }
286
287 std::vector<int32_t> refreshRateFactors = refreshRateToFactorsMap_[vsyncRate];
288 if (refreshRateFactors.empty()) {
289 return 0;
290 }
291 auto it = std::lower_bound(refreshRateFactors.begin(), refreshRateFactors.end(), targetRate);
292 if (it == refreshRateFactors.begin()) {
293 return *it;
294 } else if (it == refreshRateFactors.end()) {
295 return *(it - 1);
296 }
297 return std::abs(*it - targetRate) < std::abs(*(it - 1) - targetRate) ? *it : *(it - 1);
298 }
299
SearchMatchedRate(int32_t vsyncRate,int32_t iterCount)300 int32_t UIDisplaySync::SearchMatchedRate(int32_t vsyncRate, int32_t iterCount)
301 {
302 if (vsyncRate != 0 && iterCount >= vsyncRate) {
303 return FindMatchedRefreshRate(vsyncRate, data_->rateRange_->preferred_);
304 }
305
306 if (iterCount == 0 || vsyncRate == 0) {
307 return vsyncRate;
308 }
309
310 int32_t expectedRate = vsyncRate / iterCount;
311 if (data_->rateRange_->min_ <= expectedRate &&
312 data_->rateRange_->max_ >= expectedRate) {
313 return FindMatchedRefreshRate(vsyncRate, expectedRate);
314 }
315
316 return SearchMatchedRate(vsyncRate, ++iterCount);
317 }
318
GetCurrentContext()319 RefPtr<PipelineBase> UIDisplaySync::GetCurrentContext()
320 {
321 auto context = context_.Upgrade();
322 return context;
323 }
324
UIDisplaySync(UIObjectType uiObjectType)325 UIDisplaySync::UIDisplaySync(UIObjectType uiObjectType)
326 : uiObjectType_(uiObjectType)
327 {
328 TAG_LOGD(AceLogTag::ACE_DISPLAY_SYNC, "Create UIDisplaySync, Type: %{public}d",
329 static_cast<int32_t>(uiObjectType_));
330 }
331
UIDisplaySync()332 UIDisplaySync::UIDisplaySync() {}
333
~UIDisplaySync()334 UIDisplaySync::~UIDisplaySync() noexcept {}
335
SetExpectedFrameRateRange(const FrameRateRange & range)336 void UIDisplaySync::SetExpectedFrameRateRange(const FrameRateRange& range)
337 {
338 data_->rateRange_->Set(range.min_, range.max_, range.preferred_);
339 }
340
SetVsyncRate(int32_t vsyncRate)341 bool UIDisplaySync::SetVsyncRate(int32_t vsyncRate)
342 {
343 if (sourceVsyncRate_ == vsyncRate) {
344 return false;
345 }
346 sourceVsyncRate_ = vsyncRate;
347 return true;
348 }
349
GetDisplaySyncData() const350 RefPtr<DisplaySyncData> UIDisplaySync::GetDisplaySyncData() const
351 {
352 return data_;
353 }
354
GetAnimatorExpectedRate()355 int32_t UIDisplaySync::GetAnimatorExpectedRate()
356 {
357 // Callback from Animator
358 if (data_ && data_->onFrameWithTimestamp_ == nullptr &&
359 uiObjectType_ != UIObjectType::DISPLAYSYNC_ANIMATOR) {
360 return INVALID_ANIMATOR_EXPECTED_RATE;
361 }
362
363 int32_t animatorExpectedRate = 0;
364 if (data_ && data_->rateRange_) {
365 animatorExpectedRate = data_->rateRange_->preferred_;
366 }
367 return animatorExpectedRate;
368 }
369
IsCommonDivisor(int32_t expectedRate,int32_t vsyncRate)370 bool UIDisplaySync::IsCommonDivisor(int32_t expectedRate, int32_t vsyncRate)
371 {
372 if (expectedRate == 0 || vsyncRate == 0) {
373 return false;
374 }
375
376 int32_t n = vsyncRate / expectedRate;
377 if (expectedRate * n == vsyncRate) {
378 return true;
379 }
380 return false;
381 }
382
~UIXComponentDisplaySync()383 UIXComponentDisplaySync::~UIXComponentDisplaySync()
384 {
385 if (lastFrameRateRange_.has_value()) {
386 // -1 : means destroy
387 NotifyXComponentExpectedFrameRate(lastId_, -1);
388 }
389 }
390
NotifyXComponentExpectedFrameRate(const std::string & id)391 void UIXComponentDisplaySync::NotifyXComponentExpectedFrameRate(const std::string& id)
392 {
393 if (lastFrameRateRange_.has_value()) {
394 NotifyXComponentExpectedFrameRate(id, lastFrameRateRange_->preferred_);
395 }
396 }
397
NotifyXComponentExpectedFrameRate(const std::string & id,int32_t preferred)398 void UIXComponentDisplaySync::NotifyXComponentExpectedFrameRate(const std::string& id, int32_t preferred)
399 {
400 lastId_ = id;
401 if (lastFrameRateRange_.has_value()) {
402 #ifdef ENABLE_ROSEN_BACKEND
403 Rosen::RSInterfaces::GetInstance().NotifyXComponentExpectedFrameRate(lastId_, preferred);
404 #endif
405 }
406 }
407
NotifyXComponentExpectedFrameRate(const std::string & id,bool isOnTree,const FrameRateRange & expectedFrameRate)408 void UIXComponentDisplaySync::NotifyXComponentExpectedFrameRate(
409 const std::string& id, bool isOnTree, const FrameRateRange& expectedFrameRate)
410 {
411 SetExpectedFrameRateRange(expectedFrameRate);
412 TAG_LOGD(AceLogTag::ACE_DISPLAY_SYNC, "Id: %{public}" PRIu64 " SetExpectedFrameRateRange"
413 "{%{public}d, %{public}d, %{public}d}", GetId(),
414 expectedFrameRate.min_, expectedFrameRate.max_, expectedFrameRate.preferred_);
415 if (expectedFrameRate.preferred_ < 0 ||
416 (lastFrameRateRange_.has_value() && lastFrameRateRange_->preferred_ == expectedFrameRate.preferred_)) {
417 return;
418 }
419 lastFrameRateRange_.emplace(expectedFrameRate.min_, expectedFrameRate.max_, expectedFrameRate.preferred_);
420 if (isOnTree) {
421 NotifyXComponentExpectedFrameRate(id);
422 }
423 }
424
425 } // namespace OHOS::Ace
426