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