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