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