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