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