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