1  /*
2   * Copyright (c) 2021-2024 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_station.h"
17  
18  #include <functional>
19  
20  #include <hitrace_meter.h>
21  #include <transaction/rs_interfaces.h>
22  #include <ui/rs_ui_display_soloist.h>
23  
24  #include "window_frame_trace.h"
25  #include "window_manager_hilog.h"
26  
27  using namespace FRAME_TRACE;
28  
29  namespace OHOS {
30  namespace Rosen {
31  namespace {
32  const std::string VSYNC_THREAD_ID = "VsyncThread";
33  const std::string VSYNC_TIME_OUT_TASK = "vsync_time_out_task_";
34  constexpr int64_t VSYNC_TIME_OUT_MILLISECONDS = 600;
35  }
36  
VsyncStation(NodeId nodeId,const std::shared_ptr<AppExecFwk::EventHandler> & vsyncHandler)37  VsyncStation::VsyncStation(NodeId nodeId, const std::shared_ptr<AppExecFwk::EventHandler>& vsyncHandler)
38      : nodeId_(nodeId),
39        vsyncHandler_(vsyncHandler),
40        vsyncTimeoutTaskName_(VSYNC_TIME_OUT_TASK + std::to_string(nodeId_)),
41        frameRateLinker_(RSFrameRateLinker::Create())
42  {
43      if (!vsyncHandler_) {
44          auto mainEventRunner = AppExecFwk::EventRunner::GetMainEventRunner();
45          if (mainEventRunner != nullptr) {
46              vsyncHandler_ = std::make_shared<AppExecFwk::EventHandler>(mainEventRunner);
47          } else {
48              TLOGW(WmsLogTag::WMS_MAIN, "MainEventRunner is not available");
49              vsyncHandler_ = std::make_shared<AppExecFwk::EventHandler>(
50                  AppExecFwk::EventRunner::Create(VSYNC_THREAD_ID));
51          }
52      }
53      TLOGI(WmsLogTag::WMS_MAIN, "id %{public}" PRIu64 " created", nodeId_);
54  }
55  
~VsyncStation()56  VsyncStation::~VsyncStation()
57  {
58      TLOGI(WmsLogTag::WMS_MAIN, "id %{public}" PRIu64 " destructed", nodeId_);
59  }
60  
Destroy()61  void VsyncStation::Destroy()
62  {
63      TLOGI(WmsLogTag::WMS_MAIN, "id %{public}" PRIu64 " destroyed", nodeId_);
64      std::lock_guard<std::mutex> lock(mutex_);
65      destroyed_ = true;
66      receiver_.reset();
67      frameRateLinker_.reset();
68  }
69  
IsVsyncReceiverCreated()70  bool VsyncStation::IsVsyncReceiverCreated()
71  {
72      return GetOrCreateVsyncReceiver() != nullptr;
73  }
74  
GetOrCreateVsyncReceiver()75  std::shared_ptr<VSyncReceiver> VsyncStation::GetOrCreateVsyncReceiver()
76  {
77      std::lock_guard<std::mutex> lock(mutex_);
78      return GetOrCreateVsyncReceiverLocked();
79  }
80  
GetOrCreateVsyncReceiverLocked()81  std::shared_ptr<VSyncReceiver> VsyncStation::GetOrCreateVsyncReceiverLocked()
82  {
83      if (destroyed_) {
84          TLOGW(WmsLogTag::WMS_MAIN, "VsyncStation has been destroyed");
85          return nullptr;
86      }
87      if (receiver_ == nullptr) {
88          auto& rsClient = RSInterfaces::GetInstance();
89          auto receiver = rsClient.CreateVSyncReceiver("WM_" + std::to_string(::getprocpid()), frameRateLinker_->GetId(),
90              vsyncHandler_, nodeId_);
91          if (receiver == nullptr) {
92              TLOGE(WmsLogTag::WMS_MAIN, "Fail to create vsync receiver, nodeId: %{public}" PRIu64, nodeId_);
93              return nullptr;
94          }
95          auto result = receiver->Init();
96          if (result == VSYNC_ERROR_OK) {
97              receiver_ = std::move(receiver);
98          } else {
99              TLOGE(WmsLogTag::WMS_MAIN, "Fail to init vsync receiver, nodeId: %{public}" PRIu64
100                  ", error %{public}d", nodeId_, static_cast<int>(result));
101          }
102      }
103      return receiver_;
104  }
105  
RequestVsync(const std::shared_ptr<VsyncCallback> & vsyncCallback)106  void VsyncStation::RequestVsync(const std::shared_ptr<VsyncCallback>& vsyncCallback)
107  {
108      std::shared_ptr<VSyncReceiver> receiver;
109      {
110          std::lock_guard<std::mutex> lock(mutex_);
111          // check if receiver is ready
112          receiver = GetOrCreateVsyncReceiverLocked();
113          if (receiver == nullptr) {
114              return;
115          }
116  
117          vsyncCallbacks_.insert(vsyncCallback);
118  
119          // if Vsync has been requested, just wait callback or timeout
120          if (hasRequestedVsync_) {
121              TLOGD(WmsLogTag::WMS_MAIN, "Vsync has requested, nodeId: %{public}" PRIu64, nodeId_);
122              return;
123          }
124          hasRequestedVsync_ = true;
125  
126          if (isFirstVsyncRequest_) {
127              isFirstVsyncRequest_ = false;
128              TLOGI(WmsLogTag::WMS_MAIN, "First vsync has requested, nodeId: %{public}" PRIu64, nodeId_);
129          }
130  
131          // post timeout task for a new vsync
132          vsyncHandler_->RemoveTask(vsyncTimeoutTaskName_);
133          auto task = [weakThis = std::weak_ptr<VsyncStation>(shared_from_this())] {
134              if (auto sp = weakThis.lock()) {
135                  sp->OnVsyncTimeOut();
136              }
137          };
138          vsyncHandler_->PostTask(task, vsyncTimeoutTaskName_, VSYNC_TIME_OUT_MILLISECONDS);
139      }
140  
141      requestVsyncTimes_++;
142      WindowFrameTraceImpl::GetInstance()->VsyncStartFrameTrace();
143      auto task = [weakThis = std::weak_ptr<VsyncStation>(shared_from_this())]
144          (int64_t timestamp, int64_t frameCount, void* client) {
145          if (auto sp = weakThis.lock()) {
146              sp->VsyncCallbackInner(timestamp, frameCount);
147              WindowFrameTraceImpl::GetInstance()->VsyncStopFrameTrace();
148          }
149      };
150      receiver->RequestNextVSync({
151          .userData_ = nullptr, .callbackWithId_ = task,
152      });
153  }
154  
GetVSyncPeriod()155  int64_t VsyncStation::GetVSyncPeriod()
156  {
157      int64_t period = 0;
158      if (auto receiver = GetOrCreateVsyncReceiver()) {
159          receiver->GetVSyncPeriod(period);
160      }
161      return period;
162  }
163  
RemoveCallback()164  void VsyncStation::RemoveCallback()
165  {
166      TLOGI(WmsLogTag::WMS_MAIN, "in");
167      std::lock_guard<std::mutex> lock(mutex_);
168      vsyncCallbacks_.clear();
169  }
170  
VsyncCallbackInner(int64_t timestamp,int64_t frameCount)171  void VsyncStation::VsyncCallbackInner(int64_t timestamp, int64_t frameCount)
172  {
173      HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER,
174          "OnVsyncCallback %" PRId64 ":%" PRId64, timestamp, frameCount);
175      Callbacks vsyncCallbacks;
176      {
177          std::lock_guard<std::mutex> lock(mutex_);
178          hasRequestedVsync_ = false;
179          vsyncCallbacks = std::move(vsyncCallbacks_);
180          vsyncCallbacks_.clear();
181          vsyncHandler_->RemoveTask(vsyncTimeoutTaskName_);
182          if (isFirstVsyncBack_) {
183              isFirstVsyncBack_ = false;
184              TLOGI(WmsLogTag::WMS_MAIN, "First vsync has come back, nodeId: %{public}" PRIu64, nodeId_);
185          }
186      }
187      for (const auto& callback: vsyncCallbacks) {
188          if (callback && callback->onCallback) {
189              callback->onCallback(timestamp, frameCount);
190          }
191      }
192  }
193  
OnVsyncTimeOut()194  void VsyncStation::OnVsyncTimeOut()
195  {
196      TLOGW(WmsLogTag::WMS_MAIN, "in");
197      std::lock_guard<std::mutex> lock(mutex_);
198      hasRequestedVsync_ = false;
199  }
200  
GetFrameRateLinker()201  std::shared_ptr<RSFrameRateLinker> VsyncStation::GetFrameRateLinker()
202  {
203      std::lock_guard<std::mutex> lock(mutex_);
204      return GetFrameRateLinkerLocked();
205  }
206  
GetFrameRateLinkerLocked()207  std::shared_ptr<RSFrameRateLinker> VsyncStation::GetFrameRateLinkerLocked()
208  {
209      if (destroyed_) {
210          TLOGW(WmsLogTag::WMS_MAIN, "VsyncStation has been destroyed");
211          return nullptr;
212      }
213      return frameRateLinker_;
214  }
215  
GetFrameRateLinkerId()216  FrameRateLinkerId VsyncStation::GetFrameRateLinkerId()
217  {
218      if (auto frameRateLinker = GetFrameRateLinker()) {
219          return frameRateLinker->GetId();
220      }
221      return 0;
222  }
223  
FlushFrameRate(uint32_t rate,int32_t animatorExpectedFrameRate,uint32_t rateType)224  void VsyncStation::FlushFrameRate(uint32_t rate, int32_t animatorExpectedFrameRate, uint32_t rateType)
225  {
226      std::lock_guard<std::mutex> lock(mutex_);
227      if (auto frameRateLinker = GetFrameRateLinkerLocked()) {
228          if (lastFrameRateRange_ == nullptr) {
229              lastFrameRateRange_ = std::make_shared<FrameRateRange>(0, RANGE_MAX_REFRESHRATE, rate, rateType);
230          } else {
231              lastFrameRateRange_->Set(0, RANGE_MAX_REFRESHRATE, rate, rateType);
232          }
233          lastAnimatorExpectedFrameRate_ = animatorExpectedFrameRate;
234          if (frameRateLinker->IsEnable()) {
235              TLOGD(WmsLogTag::WMS_MAIN, "rate %{public}d, linkerId %{public}" PRIu64, rate, frameRateLinker->GetId());
236              frameRateLinker->UpdateFrameRateRange(*lastFrameRateRange_, lastAnimatorExpectedFrameRate_);
237          }
238      }
239  }
240  
SetFrameRateLinkerEnable(bool enabled)241  void VsyncStation::SetFrameRateLinkerEnable(bool enabled)
242  {
243      std::lock_guard<std::mutex> lock(mutex_);
244      if (auto frameRateLinker = GetFrameRateLinkerLocked()) {
245          if (!enabled) {
246              // clear frameRate vote
247              FrameRateRange range = {0, RANGE_MAX_REFRESHRATE, 0};
248              TLOGI(WmsLogTag::WMS_MAIN, "rate %{public}d, linkerId %{public}" PRIu64,
249                  range.preferred_, frameRateLinker->GetId());
250              frameRateLinker->UpdateFrameRateRange(range);
251              frameRateLinker->UpdateFrameRateRangeImme(range);
252          } else if (lastFrameRateRange_) {
253              // to resolve these cases:
254              // case 1: when app go backGround and haven't cleared the vote itself, the vote will be invalid forever,
255              //         so we restore the vote which is cleared here.
256              // case 2: when frameRateLinker is disabled, the frameRate vote by app will be delayed until linker enable.
257              frameRateLinker->UpdateFrameRateRange(*lastFrameRateRange_, lastAnimatorExpectedFrameRate_);
258          }
259          frameRateLinker->SetEnable(enabled);
260      }
261  }
262  
SetDisplaySoloistFrameRateLinkerEnable(bool enabled)263  void VsyncStation::SetDisplaySoloistFrameRateLinkerEnable(bool enabled)
264  {
265      {
266          std::lock_guard<std::mutex> lock(mutex_);
267          if (destroyed_) {
268              TLOGW(WmsLogTag::WMS_MAIN, "VsyncStation has been destroyed");
269              return;
270          }
271      }
272      RSDisplaySoloistManager& soloistManager = RSDisplaySoloistManager::GetInstance();
273      soloistManager.SetMainFrameRateLinkerEnable(enabled);
274  }
275  
SetUiDvsyncSwitch(bool dvsyncSwitch)276  void VsyncStation::SetUiDvsyncSwitch(bool dvsyncSwitch)
277  {
278      if (auto receiver = GetOrCreateVsyncReceiver()) {
279          receiver->SetUiDvsyncSwitch(dvsyncSwitch);
280      }
281  }
282  } // namespace Rosen
283  } // namespace OHOS
284