• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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