1 /*
2 * Copyright (c) 2023 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/form_render_window.h"
17
18 #include "base/log/frame_report.h"
19 #include "core/common/container.h"
20 #ifdef ENABLE_ROSEN_BACKEND
21 #include "core/components_ng/render/adapter/rosen_render_context.h"
22 #include "render_service_client/core/ui/rs_root_node.h"
23 #include "transaction/rs_interfaces.h"
24 #endif
25
26 namespace {
27 #ifdef ENABLE_ROSEN_BACKEND
28 constexpr float ONE_SECOND_IN_NANO = 1000000000.0f;
29
GetDisplayRefreshRate()30 float GetDisplayRefreshRate()
31 {
32 return 60.0f;
33 }
34 #endif
35 } // namespace
36
37 namespace OHOS::Ace {
38
39 #ifdef ENABLE_ROSEN_BACKEND
40 std::recursive_mutex FormRenderWindow::globalMutex_;
41 #endif
42
FormRenderWindow(RefPtr<TaskExecutor> taskExecutor,int32_t id)43 FormRenderWindow::FormRenderWindow(RefPtr<TaskExecutor> taskExecutor, int32_t id)
44 : taskExecutor_(taskExecutor), id_(id)
45 {
46 #ifdef ENABLE_ROSEN_BACKEND
47 ContainerScope scope(id);
48 auto container = Container::Current();
49 if (container != nullptr) {
50 uiContentType_ = container->GetUIContentType();
51 }
52 if (receiver_ == nullptr) {
53 auto& rsClient = Rosen::RSInterfaces::GetInstance();
54 frameRateLinker_ = Rosen::RSFrameRateLinker::Create();
55 receiver_ = rsClient.CreateVSyncReceiver("Form", frameRateLinker_ != nullptr ? frameRateLinker_->GetId() : 0);
56 if (receiver_ == nullptr) {
57 LOGE("Form Create VSync receiver failed.");
58 return;
59 }
60 receiver_->Init();
61 }
62
63 InitOnVsyncCallback();
64
65 receiver_->RequestNextVSync(frameCallback_);
66
67 rsUIDirector_ = OHOS::Rosen::RSUIDirector::Create();
68 {
69 std::lock_guard<std::recursive_mutex> lock(globalMutex_);
70 if (SystemProperties::GetMultiInstanceEnabled()) {
71 rsUIDirector_->Init(true, true); // Func Init Thread unsafe.
72 } else {
73 rsUIDirector_->Init(); // Func Init Thread unsafe.
74 }
75 }
76
77 std::string surfaceNodeName = "ArkTSCardNode";
78 struct Rosen::RSSurfaceNodeConfig surfaceNodeConfig = {.SurfaceNodeName = surfaceNodeName, .isSync = true};
79 if (SystemProperties::GetMultiInstanceEnabled()) {
80 rsSurfaceNode_ = OHOS::Rosen::RSSurfaceNode::Create(surfaceNodeConfig, true, rsUIDirector_->GetRSUIContext());
81 rsUIDirector_->SetRSSurfaceNode(rsSurfaceNode_);
82 rsUIDirector_->SetUITaskRunner([taskExecutor, id = id_](const std::function<void()>& task, uint32_t delay) {
83 ContainerScope scope(id);
84 CHECK_NULL_VOID(taskExecutor);
85 taskExecutor->PostDelayedTask(
86 task, TaskExecutor::TaskType::UI, delay, "ArkUIFormRenderServiceTask", PriorityType::HIGH);
87 }, 0, true);
88 } else {
89 rsSurfaceNode_ = OHOS::Rosen::RSSurfaceNode::Create(surfaceNodeConfig, true);
90 rsUIDirector_->SetRSSurfaceNode(rsSurfaceNode_);
91 rsUIDirector_->SetUITaskRunner([taskExecutor, id = id_](const std::function<void()>& task, uint32_t delay) {
92 ContainerScope scope(id);
93 CHECK_NULL_VOID(taskExecutor);
94 taskExecutor->PostDelayedTask(
95 task, TaskExecutor::TaskType::UI, delay, "ArkUIFormRenderServiceTask", PriorityType::HIGH);
96 }, id);
97 }
98 #else
99 taskExecutor_ = nullptr;
100 id_ = 0;
101 #endif
102 }
103
RequestFrame()104 void FormRenderWindow::RequestFrame()
105 {
106 #ifdef ENABLE_ROSEN_BACKEND
107 if (receiver_ != nullptr) {
108 if (uiContentType_ == UIContentType::DYNAMIC_COMPONENT) {
109 CHECK_NULL_VOID(!isRequestVsync_);
110 isRequestVsync_ = true;
111 }
112 receiver_->RequestNextVSync(frameCallback_);
113 }
114 #endif
115 }
116
RecordFrameTime(uint64_t timeStamp,const std::string & name)117 void FormRenderWindow::RecordFrameTime(uint64_t timeStamp, const std::string& name)
118 {
119 #ifdef ENABLE_ROSEN_BACKEND
120 if (uiContentType_ == UIContentType::DYNAMIC_COMPONENT) {
121 CHECK_NULL_VOID(rsUIDirector_);
122 rsUIDirector_->SetTimeStamp(timeStamp, name);
123 }
124 #endif
125 }
126
Destroy()127 void FormRenderWindow::Destroy()
128 {
129 TAG_LOGI(AceLogTag::ACE_FORM, "RenderWindow destroyed");
130 #ifdef ENABLE_ROSEN_BACKEND
131 frameCallback_.userData_ = nullptr;
132 frameCallback_.callback_ = nullptr;
133 rsSurfaceNode_ = nullptr;
134 if (rsUIDirector_) {
135 rsUIDirector_->Destroy();
136 rsUIDirector_.reset();
137 }
138 callbacks_.clear();
139 #endif
140 }
141
SetRootFrameNode(const RefPtr<NG::FrameNode> & root)142 void FormRenderWindow::SetRootFrameNode(const RefPtr<NG::FrameNode>& root)
143 {
144 CHECK_NULL_VOID(root);
145 #ifdef ENABLE_ROSEN_BACKEND
146 auto rosenRenderContext = AceType::DynamicCast<NG::RosenRenderContext>(root->GetRenderContext());
147 CHECK_NULL_VOID(rosenRenderContext);
148 if (rosenRenderContext->GetRSNode()) {
149 auto rootSRNode = rosenRenderContext->GetRSNode();
150 const auto& calcLayoutConstraint = root->GetLayoutProperty()->GetCalcLayoutConstraint();
151 auto width = static_cast<float>(calcLayoutConstraint->maxSize->Width()->GetDimension().Value());
152 auto height = static_cast<float>(calcLayoutConstraint->maxSize->Height()->GetDimension().Value());
153 rootSRNode->SetBounds(0, 0, width, height);
154 CHECK_NULL_VOID(rsUIDirector_);
155 rsUIDirector_->SetRSRootNode(
156 Rosen::RSNode::ReinterpretCast<Rosen::RSRootNode>(rosenRenderContext->GetRSNode()));
157 }
158 CHECK_NULL_VOID(rsUIDirector_);
159 rsUIDirector_->SendMessages();
160 #endif
161 }
162
OnShow()163 void FormRenderWindow::OnShow()
164 {
165 #ifdef ENABLE_ROSEN_BACKEND
166 Window::OnShow();
167 CHECK_NULL_VOID(rsUIDirector_);
168 rsUIDirector_->GoForeground();
169 #endif
170 }
171
OnHide()172 void FormRenderWindow::OnHide()
173 {
174 #ifdef ENABLE_ROSEN_BACKEND
175 Window::OnHide();
176 #endif
177 }
178
FlushTasks(std::function<void ()> callback)179 void FormRenderWindow::FlushTasks(std::function<void()> callback)
180 {
181 #ifdef ENABLE_ROSEN_BACKEND
182 CHECK_NULL_VOID(rsUIDirector_);
183 if (!callback) {
184 rsUIDirector_->SendMessages();
185 } else {
186 rsUIDirector_->SendMessages(callback);
187 }
188 #endif
189 }
190
Lock()191 void FormRenderWindow::Lock()
192 {
193 }
194
Unlock()195 void FormRenderWindow::Unlock()
196 {
197 }
198
GetVSyncPeriod() const199 int64_t FormRenderWindow::GetVSyncPeriod() const
200 {
201 int64_t vSyncPeriod = 0;
202 #if defined(ENABLE_ROSEN_BACKEND) && defined(__OHOS__)
203 if (receiver_) {
204 receiver_->GetVSyncPeriod(vSyncPeriod);
205 }
206 #endif
207
208 return vSyncPeriod;
209 }
210
FlushFrameRate(int32_t rate,int32_t animatorExpectedFrameRate,int32_t rateType)211 void FormRenderWindow::FlushFrameRate(int32_t rate, int32_t animatorExpectedFrameRate, int32_t rateType)
212 {
213 #ifdef ENABLE_ROSEN_BACKEND
214 if (frameRateLinker_ == nullptr) {
215 return;
216 }
217 decltype(frameRateData_) frameRateData{rate, animatorExpectedFrameRate, rateType};
218 if (frameRateData_ != frameRateData) {
219 frameRateData_ = frameRateData;
220 auto rsUIContext = rsUIDirector_ ? rsUIDirector_->GetRSUIContext() : nullptr;
221 frameRateLinker_->UpdateFrameRateRange({0, RANGE_MAX_REFRESHRATE, rate, rateType},
222 animatorExpectedFrameRate, rsUIContext);
223 }
224 #endif
225 }
226
InitOnVsyncCallback()227 void FormRenderWindow::InitOnVsyncCallback()
228 {
229 #ifdef ENABLE_ROSEN_BACKEND
230 int64_t refreshPeriod = static_cast<int64_t>(ONE_SECOND_IN_NANO / GetDisplayRefreshRate());
231 onVsyncCallback_ = [weakTask = taskExecutor_, id = id_, refreshPeriod](
232 int64_t timeStampNanos, int64_t frameCount, void* data) {
233 auto taskExecutor = weakTask.Upgrade();
234 CHECK_NULL_VOID(taskExecutor);
235 auto onVsync = [id, timeStampNanos, frameCount, refreshPeriod] {
236 int64_t ts = GetSysTimestamp();
237 ContainerScope scope(id);
238 // use container to get window can make sure the window is valid
239 auto container = Container::Current();
240 CHECK_NULL_VOID(container);
241 bool isReportFrameEvent = false;
242 auto containerHandler = container->GetContainerHandler();
243 if (containerHandler) {
244 isReportFrameEvent = containerHandler->GetHostConfig().isReportFrameEvent;
245 }
246 if (isReportFrameEvent) {
247 FrameReport::GetInstance().ReportSchedEvent(
248 FrameSchedEvent::UI_SCB_WORKER_BEGIN, {});
249 }
250 auto window = container->GetWindow();
251 CHECK_NULL_VOID(window);
252 window->OnVsync(static_cast<uint64_t>(timeStampNanos), static_cast<uint64_t>(frameCount));
253 auto pipeline = container->GetPipelineContext();
254 if (pipeline) {
255 pipeline->OnIdle(std::min(ts, timeStampNanos) + refreshPeriod);
256 }
257 if (isReportFrameEvent) {
258 FrameReport::GetInstance().ReportSchedEvent(
259 FrameSchedEvent::UI_SCB_WORKER_END, {});
260 }
261 };
262
263 ContainerScope scope(id);
264 auto uiTaskRunner = SingleTaskExecutor::Make(taskExecutor, TaskExecutor::TaskType::JS);
265 if (uiTaskRunner.IsRunOnCurrentThread()) {
266 onVsync();
267 return;
268 }
269
270 taskExecutor->PostTask(onVsync, TaskExecutor::TaskType::UI, "ArkUIFormRenderWindowVsync", PriorityType::VIP);
271 };
272
273 frameCallback_.userData_ = nullptr;
274 frameCallback_.callbackWithId_ = onVsyncCallback_;
275 #endif
276 }
277
278 } // namespace OHOS::Ace
279