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