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