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 __attribute__((no_sanitize("cfi"))) void VsyncStation::RequestVsync(
107 const std::shared_ptr<VsyncCallback>& vsyncCallback)
108 {
109 std::shared_ptr<VSyncReceiver> receiver;
110 {
111 std::lock_guard<std::mutex> lock(mutex_);
112 // check if receiver is ready
113 receiver = GetOrCreateVsyncReceiverLocked();
114 if (receiver == nullptr) {
115 return;
116 }
117
118 vsyncCallbacks_.insert(vsyncCallback);
119
120 // if Vsync has been requested, just wait callback or timeout
121 if (hasRequestedVsync_) {
122 TLOGD(WmsLogTag::WMS_MAIN, "Vsync has requested, nodeId: %{public}" PRIu64, nodeId_);
123 return;
124 }
125 hasRequestedVsync_ = true;
126
127 if (isFirstVsyncRequest_) {
128 isFirstVsyncRequest_ = false;
129 TLOGI(WmsLogTag::WMS_MAIN, "First vsync has requested, nodeId: %{public}" PRIu64, nodeId_);
130 }
131
132 // post timeout task for a new vsync
133 vsyncHandler_->RemoveTask(vsyncTimeoutTaskName_);
134 auto task = [weakThis = weak_from_this()] {
135 if (auto sp = weakThis.lock()) {
136 sp->OnVsyncTimeOut();
137 }
138 };
139 vsyncHandler_->PostTask(task, vsyncTimeoutTaskName_, VSYNC_TIME_OUT_MILLISECONDS);
140 }
141
142 WindowFrameTraceImpl::GetInstance()->VsyncStartFrameTrace();
143 auto task = [weakThis = weak_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 TLOGD(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 if (destroyed_) {
205 TLOGW(WmsLogTag::WMS_MAIN, "VsyncStation has been destroyed");
206 return nullptr;
207 }
208 return frameRateLinker_;
209 }
210
GetFrameRateLinkerId()211 FrameRateLinkerId VsyncStation::GetFrameRateLinkerId()
212 {
213 if (auto frameRateLinker = GetFrameRateLinker()) {
214 return frameRateLinker->GetId();
215 }
216 return 0;
217 }
218
FlushFrameRate(uint32_t rate, int32_t animatorExpectedFrameRate, uint32_t rateType)219 void VsyncStation::FlushFrameRate(uint32_t rate, int32_t animatorExpectedFrameRate, uint32_t rateType)
220 {
221 if (auto frameRateLinker = GetFrameRateLinker()) {
222 if (frameRateLinker->IsEnable()) {
223 TLOGD(WmsLogTag::WMS_MAIN, "rate %{public}d, linkerId %{public}" PRIu64, rate, frameRateLinker->GetId());
224 FrameRateRange range = {0, RANGE_MAX_REFRESHRATE, rate, rateType};
225 frameRateLinker->UpdateFrameRateRange(range, animatorExpectedFrameRate);
226 }
227 }
228 }
229
SetFrameRateLinkerEnable(bool enabled)230 void VsyncStation::SetFrameRateLinkerEnable(bool enabled)
231 {
232 if (auto frameRateLinker = GetFrameRateLinker()) {
233 if (!enabled) {
234 FrameRateRange range = {0, RANGE_MAX_REFRESHRATE, 0};
235 TLOGI(WmsLogTag::WMS_MAIN, "rate %{public}d, linkerId %{public}" PRIu64,
236 range.preferred_, frameRateLinker->GetId());
237 frameRateLinker->UpdateFrameRateRange(range);
238 frameRateLinker->UpdateFrameRateRangeImme(range);
239 }
240 frameRateLinker->SetEnable(enabled);
241 }
242 }
243
SetDisplaySoloistFrameRateLinkerEnable(bool enabled)244 void VsyncStation::SetDisplaySoloistFrameRateLinkerEnable(bool enabled)
245 {
246 {
247 std::lock_guard<std::mutex> lock(mutex_);
248 if (destroyed_) {
249 TLOGW(WmsLogTag::WMS_MAIN, "VsyncStation has been destroyed");
250 return;
251 }
252 }
253 RSDisplaySoloistManager& soloistManager = RSDisplaySoloistManager::GetInstance();
254 soloistManager.SetMainFrameRateLinkerEnable(enabled);
255 }
256
SetUiDvsyncSwitch(bool dvsyncSwitch)257 void VsyncStation::SetUiDvsyncSwitch(bool dvsyncSwitch)
258 {
259 if (auto receiver = GetOrCreateVsyncReceiver()) {
260 receiver->SetUiDvsyncSwitch(dvsyncSwitch);
261 }
262 }
263
264 } // namespace Rosen
265 } // namespace OHOS
266