• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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