1 /*
2 * Copyright (c) 2022 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 "core/components_ng/render/adapter/rosen_window.h"
17
18 #include "base/log/ace_performance_monitor.h"
19 #include "base/log/event_report.h"
20 #include "base/log/frame_report.h"
21 #include "base/log/jank_frame_report.h"
22 #include "core/common/container.h"
23 #include "core/components_ng/render/adapter/rosen_render_context.h"
24
25 namespace {
26 constexpr int32_t IDLE_TASK_DELAY_MILLISECOND = 51;
27 constexpr float ONE_SECOND_IN_NANO = 1000000000.0f;
28 #ifdef VSYNC_TIMEOUT_CHECK
29 constexpr int32_t VSYNC_TASK_DELAY_MILLISECOND = 3000;
30 #endif
31
32 #ifdef PREVIEW
33 constexpr float PREVIEW_REFRESH_RATE = 30.0f;
34 #endif
35 } // namespace
36
37 namespace OHOS::Ace::NG {
38
RosenWindow(const OHOS::sptr<OHOS::Rosen::Window> & window,RefPtr<TaskExecutor> taskExecutor,int32_t id)39 RosenWindow::RosenWindow(const OHOS::sptr<OHOS::Rosen::Window>& window, RefPtr<TaskExecutor> taskExecutor, int32_t id)
40 : rsWindow_(window), taskExecutor_(taskExecutor), id_(id)
41 {
42 vsyncCallback_ = std::make_shared<OHOS::Rosen::VsyncCallback>();
43 vsyncCallback_->onCallback = [weakTask = taskExecutor_, id = id_](int64_t timeStampNanos, int64_t frameCount) {
44 auto taskExecutor = weakTask.Upgrade();
45 auto onVsync = [id, timeStampNanos, frameCount] {
46 int64_t ts = GetSysTimestamp();
47 ArkUIPerfMonitor::GetInstance().StartPerf();
48 if (FrameReport::GetInstance().GetEnable()) {
49 FrameReport::GetInstance().FlushBegin();
50 }
51 ContainerScope scope(id);
52 // use container to get window can make sure the window is valid
53 auto container = Container::Current();
54 CHECK_NULL_VOID(container);
55 auto window = container->GetWindow();
56 CHECK_NULL_VOID(window);
57 int64_t refreshPeriod = window->GetVSyncPeriod();
58 window->OnVsync(static_cast<uint64_t>(timeStampNanos), static_cast<uint64_t>(frameCount));
59 ArkUIPerfMonitor::GetInstance().FinishPerf();
60 auto pipeline = container->GetPipelineContext();
61 CHECK_NULL_VOID(pipeline);
62 pipeline->OnIdle(std::min(ts, timeStampNanos) + refreshPeriod);
63 JankFrameReport::GetInstance().JankFrameRecord(timeStampNanos, window->GetWindowName());
64 if (FrameReport::GetInstance().GetEnable()) {
65 FrameReport::GetInstance().FlushEnd();
66 }
67 window->SetLastVsyncEndTimestamp(GetSysTimestamp());
68 };
69 auto uiTaskRunner = SingleTaskExecutor::Make(taskExecutor, TaskExecutor::TaskType::UI);
70 if (uiTaskRunner.IsRunOnCurrentThread()) {
71 onVsync();
72 return;
73 }
74 uiTaskRunner.PostTask([callback = std::move(onVsync)]() { callback(); }, "ArkUIRosenWindowVsync");
75 };
76 rsUIDirector_ = OHOS::Rosen::RSUIDirector::Create();
77 if (window->GetSurfaceNode()) {
78 rsUIDirector_->SetRSSurfaceNode(window->GetSurfaceNode());
79 }
80 rsUIDirector_->SetCacheDir(AceApplicationInfo::GetInstance().GetDataFileDirPath());
81 rsUIDirector_->Init();
82 rsUIDirector_->SetUITaskRunner(
83 [taskExecutor, id](const std::function<void()>& task, uint32_t delay) {
84 ContainerScope scope(id);
85 CHECK_NULL_VOID(taskExecutor);
86 taskExecutor->PostDelayedTask(
87 task, TaskExecutor::TaskType::UI, delay, "ArkUIRosenWindowRenderServiceTask", PriorityType::HIGH);
88 },
89 id);
90 rsUIDirector_->SetRequestVsyncCallback([weak = weak_from_this()]() {
91 auto self = weak.lock();
92 CHECK_NULL_VOID(self);
93 self->RequestFrame();
94 });
95 }
96
Init()97 void RosenWindow::Init()
98 {
99 CHECK_NULL_VOID(rsWindow_);
100 auto surfaceNode = rsWindow_->GetSurfaceNode();
101 if (rsUIDirector_ && surfaceNode) {
102 rsUIDirector_->SetRSSurfaceNode(surfaceNode);
103 }
104 }
105
FlushFrameRate(int32_t rate,int32_t animatorExpectedFrameRate,int32_t rateType)106 void RosenWindow::FlushFrameRate(int32_t rate, int32_t animatorExpectedFrameRate, int32_t rateType)
107 {
108 if (!rsWindow_ || rate < 0) {
109 return;
110 }
111 rsWindow_->FlushFrameRate(rate, animatorExpectedFrameRate, rateType);
112 }
113
SetUiDvsyncSwitch(bool dvsyncSwitch)114 void RosenWindow::SetUiDvsyncSwitch(bool dvsyncSwitch)
115 {
116 if (!rsWindow_) {
117 return;
118 }
119 if (dvsyncSwitch) {
120 ACE_SCOPED_TRACE("enable dvsync");
121 } else {
122 ACE_SCOPED_TRACE("disable dvsync");
123 }
124 rsWindow_->SetUiDvsyncSwitch(dvsyncSwitch);
125 }
126
RequestFrame()127 void RosenWindow::RequestFrame()
128 {
129 CHECK_NULL_VOID(onShow_);
130 CHECK_RUN_ON(UI);
131 CHECK_NULL_VOID(!isRequestVsync_);
132 auto taskExecutor = taskExecutor_.Upgrade();
133 if (rsWindow_) {
134 isRequestVsync_ = true;
135 if (isFirstRequestVsync_) {
136 isFirstRequestVsync_ = false;
137 LOGI("ArkUI requests first Vsync.");
138 }
139 rsWindow_->RequestVsync(vsyncCallback_);
140 lastRequestVsyncTime_ = static_cast<uint64_t>(GetSysTimestamp());
141 #ifdef VSYNC_TIMEOUT_CHECK
142 if (taskExecutor) {
143 auto windowId = rsWindow_->GetWindowId();
144 auto instanceId = Container::CurrentIdSafely();
145 auto task = [windowId, instanceId, timeStamp = lastRequestVsyncTime_]() {
146 LOGE("ArkUI request vsync,but no vsync was received within 3 seconds");
147 EventReport::SendVsyncException(VsyncExcepType::UI_VSYNC_TIMEOUT, windowId, instanceId, timeStamp);
148 };
149 taskExecutor->PostDelayedTaskWithoutTraceId(task, TaskExecutor::TaskType::JS,
150 VSYNC_TASK_DELAY_MILLISECOND, "ArkUIVsyncTimeoutCheck");
151 }
152 #endif
153 }
154 if (taskExecutor) {
155 taskExecutor->PostDelayedTask(
156 [id = id_]() {
157 ContainerScope scope(id);
158 auto container = Container::Current();
159 CHECK_NULL_VOID(container);
160 auto pipeline = container->GetPipelineContext();
161 CHECK_NULL_VOID(pipeline);
162 pipeline->OnIdle(0);
163 },
164 TaskExecutor::TaskType::UI, IDLE_TASK_DELAY_MILLISECOND, "ArkUIIdleTask");
165 }
166 }
167
OnShow()168 void RosenWindow::OnShow()
169 {
170 Window::OnShow();
171 CHECK_NULL_VOID(rsUIDirector_);
172 rsUIDirector_->GoForeground();
173 }
174
OnHide()175 void RosenWindow::OnHide()
176 {
177 Window::OnHide();
178 CHECK_NULL_VOID(rsUIDirector_);
179 rsUIDirector_->GoBackground();
180 rsUIDirector_->SendMessages();
181 }
182
Destroy()183 void RosenWindow::Destroy()
184 {
185 LOG_DESTROY();
186 rsWindow_ = nullptr;
187 vsyncCallback_.reset();
188 rsUIDirector_->Destroy();
189 rsUIDirector_.reset();
190 callbacks_.clear();
191 }
192
SetDrawTextAsBitmap(bool useBitmap)193 void RosenWindow::SetDrawTextAsBitmap(bool useBitmap)
194 {
195 Rosen::RSSystemProperties::SetDrawTextAsBitmap(useBitmap);
196 }
197
SetRootFrameNode(const RefPtr<NG::FrameNode> & root)198 void RosenWindow::SetRootFrameNode(const RefPtr<NG::FrameNode>& root)
199 {
200 LOGI("Rosenwindow set root frame node");
201 CHECK_NULL_VOID(root);
202 auto rosenRenderContext = AceType::DynamicCast<RosenRenderContext>(root->GetRenderContext());
203 CHECK_NULL_VOID(rosenRenderContext);
204 if (rosenRenderContext->GetRSNode()) {
205 CHECK_NULL_VOID(rsUIDirector_);
206 rsUIDirector_->SetRoot(rosenRenderContext->GetRSNode()->GetId());
207 }
208 }
209
RecordFrameTime(uint64_t timeStamp,const std::string & name)210 void RosenWindow::RecordFrameTime(uint64_t timeStamp, const std::string& name)
211 {
212 CHECK_NULL_VOID(rsUIDirector_);
213 rsUIDirector_->SetTimeStamp(timeStamp, name);
214 }
215
FlushTasks()216 void RosenWindow::FlushTasks()
217 {
218 CHECK_RUN_ON(UI);
219 CHECK_NULL_VOID(rsUIDirector_);
220 rsUIDirector_->SendMessages();
221 JankFrameReport::GetInstance().JsAnimationToRsRecord();
222 }
223
FlushLayoutSize(int32_t width,int32_t height)224 void RosenWindow::FlushLayoutSize(int32_t width, int32_t height)
225 {
226 CHECK_NULL_VOID(rsWindow_);
227 rsWindow_->FlushLayoutSize(width, height);
228 }
229
GetRefreshRate() const230 float RosenWindow::GetRefreshRate() const
231 {
232 #ifdef PREVIEW
233 return PREVIEW_REFRESH_RATE;
234 #else
235 return ONE_SECOND_IN_NANO / rsWindow_->GetVSyncPeriod();
236 #endif
237 }
238
SetKeepScreenOn(bool keepScreenOn)239 void RosenWindow::SetKeepScreenOn(bool keepScreenOn)
240 {
241 #ifdef OHOS_PLATFORM
242 if (rsWindow_) {
243 rsWindow_->SetKeepScreenOn(keepScreenOn);
244 } else {
245 LOGE("SetKeepScreenOn Rosenwindow is null");
246 }
247 #else
248 #endif
249 }
250
GetVSyncPeriod() const251 int64_t RosenWindow::GetVSyncPeriod() const
252 {
253 #ifdef PREVIEW
254 return static_cast<int64_t>(ONE_SECOND_IN_NANO / PREVIEW_REFRESH_RATE);
255 #else
256 return rsWindow_->GetVSyncPeriod();
257 #endif
258 }
259
GetWindowName() const260 std::string RosenWindow::GetWindowName() const
261 {
262 return rsWindow_->GetWindowName();
263 }
264
OnVsync(uint64_t nanoTimestamp,uint32_t frameCount)265 void RosenWindow::OnVsync(uint64_t nanoTimestamp, uint32_t frameCount)
266 {
267 Window::OnVsync(nanoTimestamp, frameCount);
268 auto taskExecutor = taskExecutor_.Upgrade();
269 #ifdef VSYNC_TIMEOUT_CHECK
270 if (taskExecutor) {
271 taskExecutor->RemoveTask(TaskExecutor::TaskType::JS, "ArkUIVsyncTimeoutCheck");
272 }
273 #endif
274 }
275 } // namespace OHOS::Ace::NG
276