• 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 <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