1e0dac50fSopenharmony_ci/* 2e0dac50fSopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3e0dac50fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4e0dac50fSopenharmony_ci * you may not use this file except in compliance with the License. 5e0dac50fSopenharmony_ci * You may obtain a copy of the License at 6e0dac50fSopenharmony_ci * 7e0dac50fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8e0dac50fSopenharmony_ci * 9e0dac50fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10e0dac50fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11e0dac50fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12e0dac50fSopenharmony_ci * See the License for the specific language governing permissions and 13e0dac50fSopenharmony_ci * limitations under the License. 14e0dac50fSopenharmony_ci */ 15e0dac50fSopenharmony_ci 16e0dac50fSopenharmony_ci#include "vsync_station.h" 17e0dac50fSopenharmony_ci 18e0dac50fSopenharmony_ci#include <functional> 19e0dac50fSopenharmony_ci 20e0dac50fSopenharmony_ci#include <hitrace_meter.h> 21e0dac50fSopenharmony_ci#include <transaction/rs_interfaces.h> 22e0dac50fSopenharmony_ci#include <ui/rs_ui_display_soloist.h> 23e0dac50fSopenharmony_ci 24e0dac50fSopenharmony_ci#include "window_frame_trace.h" 25e0dac50fSopenharmony_ci#include "window_manager_hilog.h" 26e0dac50fSopenharmony_ci 27e0dac50fSopenharmony_ciusing namespace FRAME_TRACE; 28e0dac50fSopenharmony_ci 29e0dac50fSopenharmony_cinamespace OHOS { 30e0dac50fSopenharmony_cinamespace Rosen { 31e0dac50fSopenharmony_cinamespace { 32e0dac50fSopenharmony_ciconst std::string VSYNC_THREAD_ID = "VsyncThread"; 33e0dac50fSopenharmony_ciconst std::string VSYNC_TIME_OUT_TASK = "vsync_time_out_task_"; 34e0dac50fSopenharmony_ciconstexpr int64_t VSYNC_TIME_OUT_MILLISECONDS = 600; 35e0dac50fSopenharmony_ci} 36e0dac50fSopenharmony_ci 37e0dac50fSopenharmony_ciVsyncStation::VsyncStation(NodeId nodeId, const std::shared_ptr<AppExecFwk::EventHandler>& vsyncHandler) 38e0dac50fSopenharmony_ci : nodeId_(nodeId), 39e0dac50fSopenharmony_ci vsyncHandler_(vsyncHandler), 40e0dac50fSopenharmony_ci vsyncTimeoutTaskName_(VSYNC_TIME_OUT_TASK + std::to_string(nodeId)), 41e0dac50fSopenharmony_ci frameRateLinker_(RSFrameRateLinker::Create()) 42e0dac50fSopenharmony_ci{ 43e0dac50fSopenharmony_ci if (!vsyncHandler_) { 44e0dac50fSopenharmony_ci auto mainEventRunner = AppExecFwk::EventRunner::GetMainEventRunner(); 45e0dac50fSopenharmony_ci if (mainEventRunner != nullptr) { 46e0dac50fSopenharmony_ci vsyncHandler_ = std::make_shared<AppExecFwk::EventHandler>(mainEventRunner); 47e0dac50fSopenharmony_ci } else { 48e0dac50fSopenharmony_ci TLOGW(WmsLogTag::WMS_MAIN, "MainEventRunner is not available"); 49e0dac50fSopenharmony_ci vsyncHandler_ = std::make_shared<AppExecFwk::EventHandler>( 50e0dac50fSopenharmony_ci AppExecFwk::EventRunner::Create(VSYNC_THREAD_ID)); 51e0dac50fSopenharmony_ci } 52e0dac50fSopenharmony_ci } 53e0dac50fSopenharmony_ci TLOGI(WmsLogTag::WMS_MAIN, "id %{public}" PRIu64 " created", nodeId_); 54e0dac50fSopenharmony_ci} 55e0dac50fSopenharmony_ci 56e0dac50fSopenharmony_ciVsyncStation::~VsyncStation() 57e0dac50fSopenharmony_ci{ 58e0dac50fSopenharmony_ci TLOGI(WmsLogTag::WMS_MAIN, "id %{public}" PRIu64 " destructed", nodeId_); 59e0dac50fSopenharmony_ci} 60e0dac50fSopenharmony_ci 61e0dac50fSopenharmony_civoid VsyncStation::Destroy() 62e0dac50fSopenharmony_ci{ 63e0dac50fSopenharmony_ci TLOGI(WmsLogTag::WMS_MAIN, "id %{public}" PRIu64 " destroyed", nodeId_); 64e0dac50fSopenharmony_ci std::lock_guard<std::mutex> lock(mutex_); 65e0dac50fSopenharmony_ci destroyed_ = true; 66e0dac50fSopenharmony_ci receiver_.reset(); 67e0dac50fSopenharmony_ci frameRateLinker_.reset(); 68e0dac50fSopenharmony_ci} 69e0dac50fSopenharmony_ci 70e0dac50fSopenharmony_cibool VsyncStation::IsVsyncReceiverCreated() 71e0dac50fSopenharmony_ci{ 72e0dac50fSopenharmony_ci return GetOrCreateVsyncReceiver() != nullptr; 73e0dac50fSopenharmony_ci} 74e0dac50fSopenharmony_ci 75e0dac50fSopenharmony_cistd::shared_ptr<VSyncReceiver> VsyncStation::GetOrCreateVsyncReceiver() 76e0dac50fSopenharmony_ci{ 77e0dac50fSopenharmony_ci std::lock_guard<std::mutex> lock(mutex_); 78e0dac50fSopenharmony_ci return GetOrCreateVsyncReceiverLocked(); 79e0dac50fSopenharmony_ci} 80e0dac50fSopenharmony_ci 81e0dac50fSopenharmony_cistd::shared_ptr<VSyncReceiver> VsyncStation::GetOrCreateVsyncReceiverLocked() 82e0dac50fSopenharmony_ci{ 83e0dac50fSopenharmony_ci if (destroyed_) { 84e0dac50fSopenharmony_ci TLOGW(WmsLogTag::WMS_MAIN, "VsyncStation has been destroyed"); 85e0dac50fSopenharmony_ci return nullptr; 86e0dac50fSopenharmony_ci } 87e0dac50fSopenharmony_ci if (receiver_ == nullptr) { 88e0dac50fSopenharmony_ci auto& rsClient = RSInterfaces::GetInstance(); 89e0dac50fSopenharmony_ci auto receiver = rsClient.CreateVSyncReceiver("WM_" + std::to_string(::getprocpid()), frameRateLinker_->GetId(), 90e0dac50fSopenharmony_ci vsyncHandler_, nodeId_); 91e0dac50fSopenharmony_ci if (receiver == nullptr) { 92e0dac50fSopenharmony_ci TLOGE(WmsLogTag::WMS_MAIN, "Fail to create vsync receiver, nodeId: %{public}" PRIu64, nodeId_); 93e0dac50fSopenharmony_ci return nullptr; 94e0dac50fSopenharmony_ci } 95e0dac50fSopenharmony_ci auto result = receiver->Init(); 96e0dac50fSopenharmony_ci if (result == VSYNC_ERROR_OK) { 97e0dac50fSopenharmony_ci receiver_ = std::move(receiver); 98e0dac50fSopenharmony_ci } else { 99e0dac50fSopenharmony_ci TLOGE(WmsLogTag::WMS_MAIN, "Fail to init vsync receiver, nodeId: %{public}" PRIu64 100e0dac50fSopenharmony_ci ", error %{public}d", nodeId_, static_cast<int>(result)); 101e0dac50fSopenharmony_ci } 102e0dac50fSopenharmony_ci } 103e0dac50fSopenharmony_ci return receiver_; 104e0dac50fSopenharmony_ci} 105e0dac50fSopenharmony_ci 106e0dac50fSopenharmony_ci__attribute__((no_sanitize("cfi"))) void VsyncStation::RequestVsync( 107e0dac50fSopenharmony_ci const std::shared_ptr<VsyncCallback>& vsyncCallback) 108e0dac50fSopenharmony_ci{ 109e0dac50fSopenharmony_ci std::shared_ptr<VSyncReceiver> receiver; 110e0dac50fSopenharmony_ci { 111e0dac50fSopenharmony_ci std::lock_guard<std::mutex> lock(mutex_); 112e0dac50fSopenharmony_ci // check if receiver is ready 113e0dac50fSopenharmony_ci receiver = GetOrCreateVsyncReceiverLocked(); 114e0dac50fSopenharmony_ci if (receiver == nullptr) { 115e0dac50fSopenharmony_ci return; 116e0dac50fSopenharmony_ci } 117e0dac50fSopenharmony_ci 118e0dac50fSopenharmony_ci vsyncCallbacks_.insert(vsyncCallback); 119e0dac50fSopenharmony_ci 120e0dac50fSopenharmony_ci // if Vsync has been requested, just wait callback or timeout 121e0dac50fSopenharmony_ci if (hasRequestedVsync_) { 122e0dac50fSopenharmony_ci TLOGD(WmsLogTag::WMS_MAIN, "Vsync has requested, nodeId: %{public}" PRIu64, nodeId_); 123e0dac50fSopenharmony_ci return; 124e0dac50fSopenharmony_ci } 125e0dac50fSopenharmony_ci hasRequestedVsync_ = true; 126e0dac50fSopenharmony_ci 127e0dac50fSopenharmony_ci if (isFirstVsyncRequest_) { 128e0dac50fSopenharmony_ci isFirstVsyncRequest_ = false; 129e0dac50fSopenharmony_ci TLOGI(WmsLogTag::WMS_MAIN, "First vsync has requested, nodeId: %{public}" PRIu64, nodeId_); 130e0dac50fSopenharmony_ci } 131e0dac50fSopenharmony_ci 132e0dac50fSopenharmony_ci // post timeout task for a new vsync 133e0dac50fSopenharmony_ci vsyncHandler_->RemoveTask(vsyncTimeoutTaskName_); 134e0dac50fSopenharmony_ci auto task = [weakThis = weak_from_this()] { 135e0dac50fSopenharmony_ci if (auto sp = weakThis.lock()) { 136e0dac50fSopenharmony_ci sp->OnVsyncTimeOut(); 137e0dac50fSopenharmony_ci } 138e0dac50fSopenharmony_ci }; 139e0dac50fSopenharmony_ci vsyncHandler_->PostTask(task, vsyncTimeoutTaskName_, VSYNC_TIME_OUT_MILLISECONDS); 140e0dac50fSopenharmony_ci } 141e0dac50fSopenharmony_ci 142e0dac50fSopenharmony_ci WindowFrameTraceImpl::GetInstance()->VsyncStartFrameTrace(); 143e0dac50fSopenharmony_ci auto task = [weakThis = weak_from_this()] 144e0dac50fSopenharmony_ci (int64_t timestamp, int64_t frameCount, void* client) { 145e0dac50fSopenharmony_ci if (auto sp = weakThis.lock()) { 146e0dac50fSopenharmony_ci sp->VsyncCallbackInner(timestamp, frameCount); 147e0dac50fSopenharmony_ci WindowFrameTraceImpl::GetInstance()->VsyncStopFrameTrace(); 148e0dac50fSopenharmony_ci } 149e0dac50fSopenharmony_ci }; 150e0dac50fSopenharmony_ci receiver->RequestNextVSync({ 151e0dac50fSopenharmony_ci .userData_ = nullptr, .callbackWithId_ = task, 152e0dac50fSopenharmony_ci }); 153e0dac50fSopenharmony_ci} 154e0dac50fSopenharmony_ci 155e0dac50fSopenharmony_ciint64_t VsyncStation::GetVSyncPeriod() 156e0dac50fSopenharmony_ci{ 157e0dac50fSopenharmony_ci int64_t period = 0; 158e0dac50fSopenharmony_ci if (auto receiver = GetOrCreateVsyncReceiver()) { 159e0dac50fSopenharmony_ci receiver->GetVSyncPeriod(period); 160e0dac50fSopenharmony_ci } 161e0dac50fSopenharmony_ci return period; 162e0dac50fSopenharmony_ci} 163e0dac50fSopenharmony_ci 164e0dac50fSopenharmony_civoid VsyncStation::RemoveCallback() 165e0dac50fSopenharmony_ci{ 166e0dac50fSopenharmony_ci TLOGI(WmsLogTag::WMS_MAIN, "in"); 167e0dac50fSopenharmony_ci std::lock_guard<std::mutex> lock(mutex_); 168e0dac50fSopenharmony_ci vsyncCallbacks_.clear(); 169e0dac50fSopenharmony_ci} 170e0dac50fSopenharmony_ci 171e0dac50fSopenharmony_civoid VsyncStation::VsyncCallbackInner(int64_t timestamp, int64_t frameCount) 172e0dac50fSopenharmony_ci{ 173e0dac50fSopenharmony_ci HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, 174e0dac50fSopenharmony_ci "OnVsyncCallback %" PRId64 ":%" PRId64, timestamp, frameCount); 175e0dac50fSopenharmony_ci Callbacks vsyncCallbacks; 176e0dac50fSopenharmony_ci { 177e0dac50fSopenharmony_ci std::lock_guard<std::mutex> lock(mutex_); 178e0dac50fSopenharmony_ci hasRequestedVsync_ = false; 179e0dac50fSopenharmony_ci vsyncCallbacks = std::move(vsyncCallbacks_); 180e0dac50fSopenharmony_ci vsyncCallbacks_.clear(); 181e0dac50fSopenharmony_ci vsyncHandler_->RemoveTask(vsyncTimeoutTaskName_); 182e0dac50fSopenharmony_ci if (isFirstVsyncBack_) { 183e0dac50fSopenharmony_ci isFirstVsyncBack_ = false; 184e0dac50fSopenharmony_ci TLOGI(WmsLogTag::WMS_MAIN, "First vsync has come back, nodeId: %{public}" PRIu64, nodeId_); 185e0dac50fSopenharmony_ci } 186e0dac50fSopenharmony_ci } 187e0dac50fSopenharmony_ci for (const auto& callback: vsyncCallbacks) { 188e0dac50fSopenharmony_ci if (callback && callback->onCallback) { 189e0dac50fSopenharmony_ci callback->onCallback(timestamp, frameCount); 190e0dac50fSopenharmony_ci } 191e0dac50fSopenharmony_ci } 192e0dac50fSopenharmony_ci} 193e0dac50fSopenharmony_ci 194e0dac50fSopenharmony_civoid VsyncStation::OnVsyncTimeOut() 195e0dac50fSopenharmony_ci{ 196e0dac50fSopenharmony_ci TLOGD(WmsLogTag::WMS_MAIN, "in"); 197e0dac50fSopenharmony_ci std::lock_guard<std::mutex> lock(mutex_); 198e0dac50fSopenharmony_ci hasRequestedVsync_ = false; 199e0dac50fSopenharmony_ci} 200e0dac50fSopenharmony_ci 201e0dac50fSopenharmony_cistd::shared_ptr<RSFrameRateLinker> VsyncStation::GetFrameRateLinker() 202e0dac50fSopenharmony_ci{ 203e0dac50fSopenharmony_ci std::lock_guard<std::mutex> lock(mutex_); 204e0dac50fSopenharmony_ci if (destroyed_) { 205e0dac50fSopenharmony_ci TLOGW(WmsLogTag::WMS_MAIN, "VsyncStation has been destroyed"); 206e0dac50fSopenharmony_ci return nullptr; 207e0dac50fSopenharmony_ci } 208e0dac50fSopenharmony_ci return frameRateLinker_; 209e0dac50fSopenharmony_ci} 210e0dac50fSopenharmony_ci 211e0dac50fSopenharmony_ciFrameRateLinkerId VsyncStation::GetFrameRateLinkerId() 212e0dac50fSopenharmony_ci{ 213e0dac50fSopenharmony_ci if (auto frameRateLinker = GetFrameRateLinker()) { 214e0dac50fSopenharmony_ci return frameRateLinker->GetId(); 215e0dac50fSopenharmony_ci } 216e0dac50fSopenharmony_ci return 0; 217e0dac50fSopenharmony_ci} 218e0dac50fSopenharmony_ci 219e0dac50fSopenharmony_civoid VsyncStation::FlushFrameRate(uint32_t rate, int32_t animatorExpectedFrameRate, uint32_t rateType) 220e0dac50fSopenharmony_ci{ 221e0dac50fSopenharmony_ci if (auto frameRateLinker = GetFrameRateLinker()) { 222e0dac50fSopenharmony_ci if (frameRateLinker->IsEnable()) { 223e0dac50fSopenharmony_ci TLOGD(WmsLogTag::WMS_MAIN, "rate %{public}d, linkerId %{public}" PRIu64, rate, frameRateLinker->GetId()); 224e0dac50fSopenharmony_ci FrameRateRange range = {0, RANGE_MAX_REFRESHRATE, rate, rateType}; 225e0dac50fSopenharmony_ci frameRateLinker->UpdateFrameRateRange(range, animatorExpectedFrameRate); 226e0dac50fSopenharmony_ci } 227e0dac50fSopenharmony_ci } 228e0dac50fSopenharmony_ci} 229e0dac50fSopenharmony_ci 230e0dac50fSopenharmony_civoid VsyncStation::SetFrameRateLinkerEnable(bool enabled) 231e0dac50fSopenharmony_ci{ 232e0dac50fSopenharmony_ci if (auto frameRateLinker = GetFrameRateLinker()) { 233e0dac50fSopenharmony_ci if (!enabled) { 234e0dac50fSopenharmony_ci FrameRateRange range = {0, RANGE_MAX_REFRESHRATE, 0}; 235e0dac50fSopenharmony_ci TLOGI(WmsLogTag::WMS_MAIN, "rate %{public}d, linkerId %{public}" PRIu64, 236e0dac50fSopenharmony_ci range.preferred_, frameRateLinker->GetId()); 237e0dac50fSopenharmony_ci frameRateLinker->UpdateFrameRateRange(range); 238e0dac50fSopenharmony_ci frameRateLinker->UpdateFrameRateRangeImme(range); 239e0dac50fSopenharmony_ci } 240e0dac50fSopenharmony_ci frameRateLinker->SetEnable(enabled); 241e0dac50fSopenharmony_ci } 242e0dac50fSopenharmony_ci} 243e0dac50fSopenharmony_ci 244e0dac50fSopenharmony_civoid VsyncStation::SetDisplaySoloistFrameRateLinkerEnable(bool enabled) 245e0dac50fSopenharmony_ci{ 246e0dac50fSopenharmony_ci { 247e0dac50fSopenharmony_ci std::lock_guard<std::mutex> lock(mutex_); 248e0dac50fSopenharmony_ci if (destroyed_) { 249e0dac50fSopenharmony_ci TLOGW(WmsLogTag::WMS_MAIN, "VsyncStation has been destroyed"); 250e0dac50fSopenharmony_ci return; 251e0dac50fSopenharmony_ci } 252e0dac50fSopenharmony_ci } 253e0dac50fSopenharmony_ci RSDisplaySoloistManager& soloistManager = RSDisplaySoloistManager::GetInstance(); 254e0dac50fSopenharmony_ci soloistManager.SetMainFrameRateLinkerEnable(enabled); 255e0dac50fSopenharmony_ci} 256e0dac50fSopenharmony_ci 257e0dac50fSopenharmony_civoid VsyncStation::SetUiDvsyncSwitch(bool dvsyncSwitch) 258e0dac50fSopenharmony_ci{ 259e0dac50fSopenharmony_ci if (auto receiver = GetOrCreateVsyncReceiver()) { 260e0dac50fSopenharmony_ci receiver->SetUiDvsyncSwitch(dvsyncSwitch); 261e0dac50fSopenharmony_ci } 262e0dac50fSopenharmony_ci} 263e0dac50fSopenharmony_ci 264e0dac50fSopenharmony_ci} // namespace Rosen 265e0dac50fSopenharmony_ci} // namespace OHOS 266