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