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