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