1 /*
2 * Copyright (c) 2022-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/pipeline_ng/ui_task_scheduler.h"
17
18 #include "base/log/ace_performance_check.h"
19 #include "base/log/frame_report.h"
20 #include "base/memory/referenced.h"
21 #include "base/utils/time_util.h"
22 #include "base/utils/utils.h"
23 #include "core/common/thread_checker.h"
24 #include "core/components_ng/base/frame_node.h"
25
26 namespace OHOS::Ace::NG {
27 uint64_t UITaskScheduler::frameId_ = 0;
28
29 UITaskScheduler::~UITaskScheduler() = default;
30
AddDirtyLayoutNode(const RefPtr<FrameNode> & dirty)31 void UITaskScheduler::AddDirtyLayoutNode(const RefPtr<FrameNode>& dirty)
32 {
33 CHECK_RUN_ON(UI);
34 CHECK_NULL_VOID(dirty);
35 dirtyLayoutNodes_.emplace_back(dirty);
36 }
37
AddDirtyRenderNode(const RefPtr<FrameNode> & dirty)38 void UITaskScheduler::AddDirtyRenderNode(const RefPtr<FrameNode>& dirty)
39 {
40 CHECK_RUN_ON(UI);
41 CHECK_NULL_VOID(dirty);
42 auto result = dirtyRenderNodes_[dirty->GetPageId()].emplace(dirty);
43 if (!result.second) {
44 LOGW("fail to emplace %{public}s render node", dirty->GetTag().c_str());
45 }
46 }
47
FlushLayoutTask(bool forceUseMainThread)48 void UITaskScheduler::FlushLayoutTask(bool forceUseMainThread)
49 {
50 CHECK_RUN_ON(UI);
51 ACE_FUNCTION_TRACE();
52 if (dirtyLayoutNodes_.empty()) {
53 return;
54 }
55 isLayouting_ = true;
56 auto dirtyLayoutNodes = std::move(dirtyLayoutNodes_);
57 PageDirtySet dirtyLayoutNodesSet(dirtyLayoutNodes.begin(), dirtyLayoutNodes.end());
58
59 // Priority task creation
60 int64_t time = 0;
61 for (auto&& node : dirtyLayoutNodesSet) {
62 // need to check the node is destroying or not before CreateLayoutTask
63 if (!node || node->IsInDestroying()) {
64 continue;
65 }
66 time = GetSysTimestamp();
67 auto task = node->CreateLayoutTask(forceUseMainThread);
68 if (task) {
69 if (forceUseMainThread || (task->GetTaskThreadType() == MAIN_TASK)) {
70 (*task)();
71 time = GetSysTimestamp() - time;
72 } else {
73 LOGW("need to use multithread feature");
74 }
75 }
76 if (frameInfo_ != nullptr) {
77 frameInfo_->AddTaskInfo(node->GetTag(), node->GetId(), time, FrameInfo::TaskType::LAYOUT);
78 }
79 }
80 isLayouting_ = false;
81 }
82
FlushRenderTask(bool forceUseMainThread)83 void UITaskScheduler::FlushRenderTask(bool forceUseMainThread)
84 {
85 CHECK_RUN_ON(UI);
86 if (FrameReport::GetInstance().GetEnable()) {
87 FrameReport::GetInstance().BeginFlushRender();
88 }
89 auto dirtyRenderNodes = std::move(dirtyRenderNodes_);
90 // Priority task creation
91 int64_t time = 0;
92 for (auto&& pageNodes : dirtyRenderNodes) {
93 ACE_SCOPED_TRACE("FlushRenderTask %zu", pageNodes.second.size());
94 for (auto&& node : pageNodes.second) {
95 if (!node) {
96 continue;
97 }
98 if (node->IsInDestroying()) {
99 continue;
100 }
101 time = GetSysTimestamp();
102 auto task = node->CreateRenderTask(forceUseMainThread);
103 if (task) {
104 if (forceUseMainThread || (task->GetTaskThreadType() == MAIN_TASK)) {
105 (*task)();
106 time = GetSysTimestamp() - time;
107 if (frameInfo_ != nullptr) {
108 frameInfo_->AddTaskInfo(node->GetTag(), node->GetId(), time, FrameInfo::TaskType::RENDER);
109 }
110 } else {
111 LOGW("need to use multithread feature");
112 }
113 }
114 }
115 }
116 }
117
NeedAdditionalLayout()118 bool UITaskScheduler::NeedAdditionalLayout()
119 {
120 bool ret = false;
121 ElementRegister::GetInstance()->ReSyncGeometryTransition();
122
123 RootDirtyMap dirtyLayoutNodesMap;
124 for (auto&& dirty : dirtyLayoutNodes_) {
125 dirtyLayoutNodesMap[dirty->GetPageId()].emplace(dirty);
126 }
127
128 for (auto&& pageNodes : dirtyLayoutNodesMap) {
129 for (auto&& node : pageNodes.second) {
130 if (!node || !node->GetLayoutProperty()) {
131 continue;
132 }
133 const auto& geometryTransition = node->GetLayoutProperty()->GetGeometryTransition();
134 if (geometryTransition != nullptr) {
135 ret |= geometryTransition->OnAdditionalLayout(node);
136 }
137 }
138 }
139 return ret;
140 }
141
FlushTask()142 void UITaskScheduler::FlushTask()
143 {
144 CHECK_RUN_ON(UI);
145 ACE_SCOPED_TRACE("UITaskScheduler::FlushTask");
146 FlushLayoutTask();
147 if (NeedAdditionalLayout()) {
148 FlushLayoutTask();
149 }
150 if (!afterLayoutTasks_.empty()) {
151 FlushAfterLayoutTask();
152 }
153 ElementRegister::GetInstance()->ClearPendingRemoveNodes();
154 FlushRenderTask();
155 }
156
AddPredictTask(PredictTask && task)157 void UITaskScheduler::AddPredictTask(PredictTask&& task)
158 {
159 predictTask_.push_back(std::move(task));
160 }
161
FlushPredictTask(int64_t deadline,bool canUseLongPredictTask)162 void UITaskScheduler::FlushPredictTask(int64_t deadline, bool canUseLongPredictTask)
163 {
164 decltype(predictTask_) tasks(std::move(predictTask_));
165 for (const auto& task : tasks) {
166 if (task) {
167 task(deadline, canUseLongPredictTask);
168 }
169 }
170 }
171
CleanUp()172 void UITaskScheduler::CleanUp()
173 {
174 dirtyLayoutNodes_.clear();
175 dirtyRenderNodes_.clear();
176 }
177
isEmpty()178 bool UITaskScheduler::isEmpty()
179 {
180 return dirtyLayoutNodes_.empty() && dirtyRenderNodes_.empty();
181 }
182
AddAfterLayoutTask(std::function<void ()> && task)183 void UITaskScheduler::AddAfterLayoutTask(std::function<void()>&& task)
184 {
185 afterLayoutTasks_.emplace_back(std::move(task));
186 }
187
FlushAfterLayoutTask()188 void UITaskScheduler::FlushAfterLayoutTask()
189 {
190 decltype(afterLayoutTasks_) tasks(std::move(afterLayoutTasks_));
191 for (const auto& task : tasks) {
192 if (task) {
193 task();
194 }
195 }
196 }
197
AddAfterRenderTask(std::function<void ()> && task)198 void UITaskScheduler::AddAfterRenderTask(std::function<void()>&& task)
199 {
200 afterRenderTasks_.emplace_back(std::move(task));
201 }
202
FlushAfterRenderTask()203 void UITaskScheduler::FlushAfterRenderTask()
204 {
205 ACE_SCOPED_TRACE("UITaskScheduler::FlushAfterRenderTask");
206 decltype(afterRenderTasks_) tasks(std::move(afterRenderTasks_));
207 for (const auto& task : tasks) {
208 if (task) {
209 task();
210 }
211 }
212 }
213
214 } // namespace OHOS::Ace::NG
215