1 /*
2 * Copyright (c) 2021 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 "pipeline/rs_render_thread.h"
17
18 #include <ctime>
19
20 #include "base/hiviewdfx/hisysevent/interfaces/native/innerkits/hisysevent/include/hisysevent.h"
21
22 #include "pipeline/rs_frame_report.h"
23 #include "pipeline/rs_render_node_map.h"
24 #include "pipeline/rs_root_render_node.h"
25 #include "platform/common/rs_log.h"
26 #include "rs_trace.h"
27 #include "ui/rs_ui_director.h"
28 #ifdef ROSEN_OHOS
29 #include <sys/prctl.h>
30 #include <unistd.h>
31
32 #include "platform/ohos/rs_render_service_connect_hub.h"
33 #endif
34 #ifdef USE_FLUTTER_TEXTURE
35 #include "pipeline/rs_texture_render_node.h"
36 #endif
37
SystemCallSetThreadName(const std::string & name)38 static void SystemCallSetThreadName(const std::string& name)
39 {
40 #ifdef ROSEN_OHOS
41 if (prctl(PR_SET_NAME, name.c_str()) < 0) {
42 return;
43 }
44 #endif
45 }
46
47 namespace {
DrawEventReport(float frameLength)48 void DrawEventReport(float frameLength)
49 {
50 int32_t pid = getpid();
51 uint32_t uid = getuid();
52 std::string domain = "GRAPHIC";
53 std::string stringId = "NO_DRAW";
54 std::string processName = "RS_THREAD";
55 std::string msg = "It took " + std::to_string(frameLength * 1000) + "ms to draw."; // 1s = 1000ms
56
57 OHOS::HiviewDFX::HiSysEvent::Write(domain, stringId,
58 OHOS::HiviewDFX::HiSysEvent::EventType::FAULT,
59 "PID", pid,
60 "UID", uid,
61 "PROCESS_NAME", processName,
62 "MSG", msg);
63 }
64 }
65
66 namespace OHOS {
67 namespace Rosen {
Instance()68 RSRenderThread& RSRenderThread::Instance()
69 {
70 static RSRenderThread renderThread;
71 return renderThread;
72 }
73
RSRenderThread()74 RSRenderThread::RSRenderThread()
75 {
76 #ifdef ACE_ENABLE_GL
77 renderContext_ = new RenderContext();
78 ROSEN_LOGD("Create RenderContext, its pointer is %p", renderContext_);
79 #endif
80 mainFunc_ = [&]() {
81 clock_t startTime = clock();
82 ROSEN_TRACE_BEGIN(BYTRACE_TAG_GRAPHIC_AGP, "RSRenderThread::DrawFrame");
83 {
84 prevTimestamp_ = timestamp_;
85 ProcessCommands();
86 }
87
88 ROSEN_LOGD("RSRenderThread DrawFrame(%llu) in %s", prevTimestamp_, renderContext_ ? "GPU" : "CPU");
89 Animate(prevTimestamp_);
90 Render();
91 RS_ASYNC_TRACE_BEGIN("waiting GPU running", 1111); // 1111 means async trace code for gpu
92 SendCommands();
93 auto transactionProxy = RSTransactionProxy::GetInstance();
94 if (transactionProxy != nullptr) {
95 transactionProxy->FlushImplicitTransactionFromRT();
96 }
97 ROSEN_TRACE_END(BYTRACE_TAG_GRAPHIC_AGP);
98 clock_t endTime = clock();
99 float drawTime = endTime - startTime;
100 // Due to the calibration problem, there is a larger error on the windows.
101 if (drawTime > CLOCKS_PER_SEC * 6) { // The drawing timeout reaches 6 seconds.
102 drawTime = static_cast<float>(drawTime) / CLOCKS_PER_SEC;
103 DrawEventReport(drawTime);
104 ROSEN_LOGD("RSRenderThread DrawFrame took %fs.", drawTime);
105 }
106 };
107 }
108
~RSRenderThread()109 RSRenderThread::~RSRenderThread()
110 {
111 Stop();
112
113 if (renderContext_ != nullptr) {
114 ROSEN_LOGD("Destory renderContext!!");
115 delete renderContext_;
116 renderContext_ = nullptr;
117 }
118 }
119
Start()120 void RSRenderThread::Start()
121 {
122 ROSEN_LOGD("RSRenderThread start.");
123 running_.store(true);
124 if (thread_ == nullptr) {
125 thread_ = std::make_unique<std::thread>(&RSRenderThread::RenderLoop, this);
126 }
127
128 #ifdef ROSEN_OHOS
129 RSRenderServiceConnectHub::SetOnConnectCallback(
130 [weakThis = wptr<RSRenderThread>(this)](sptr<RSIRenderServiceConnection>& conn) {
131 sptr<IApplicationRenderThread> renderThreadSptr = weakThis.promote();
132 if (renderThreadSptr == nullptr) {
133 return;
134 }
135 conn->RegisterApplicationRenderThread(getpid(), renderThreadSptr);
136 });
137 #endif
138 }
139
Stop()140 void RSRenderThread::Stop()
141 {
142 running_.store(false);
143 WakeUp();
144
145 if (thread_ != nullptr && thread_->joinable()) {
146 thread_->join();
147 }
148
149 thread_ = nullptr;
150 ROSEN_LOGD("RSRenderThread stopped.");
151 }
152
WakeUp()153 void RSRenderThread::WakeUp()
154 {
155 if (rendererLooper_ != nullptr) {
156 rendererLooper_->WakeUp();
157 }
158 }
159
RecvTransactionData(std::unique_ptr<RSTransactionData> & transactionData)160 void RSRenderThread::RecvTransactionData(std::unique_ptr<RSTransactionData>& transactionData)
161 {
162 {
163 std::unique_lock<std::mutex> cmdLock(cmdMutex_);
164 cmds_.emplace_back(std::move(transactionData));
165 }
166 // [PLANNING]: process in next vsync (temporarily)
167 RSRenderThread::Instance().RequestNextVSync();
168 }
169
RequestNextVSync()170 void RSRenderThread::RequestNextVSync()
171 {
172 RS_TRACE_FUNC();
173 if (vsyncClient_ != nullptr) {
174 vsyncClient_->RequestNextVsync();
175 }
176 }
177
GetTid()178 int32_t RSRenderThread::GetTid()
179 {
180 return tid_;
181 }
182
RenderLoop()183 void RSRenderThread::RenderLoop()
184 {
185 SystemCallSetThreadName("RSRenderThread");
186 rendererLooper_ = RSThreadLooper::Create();
187 threadHandler_ = RSThreadHandler::Create();
188
189 #ifdef ROSEN_OHOS
190 tid_ = gettid();
191 vsyncClient_ = RSVsyncClient::Create();
192 if (vsyncClient_) {
193 vsyncClient_->SetVsyncCallback(std::bind(&RSRenderThread::OnVsync, this, std::placeholders::_1));
194 }
195 #endif
196 #ifdef ACE_ENABLE_GL
197 renderContext_->InitializeEglContext(); // init egl context on RT
198 #endif
199
200 while (running_.load()) {
201 if (rendererLooper_ == nullptr) {
202 break;
203 }
204 {
205 if (preTask_ != nullptr) {
206 threadHandler_->PostTask(preTask_);
207 preTask_ = nullptr;
208 }
209 }
210 if (running_.load()) {
211 rendererLooper_->ProcessAllMessages(-1);
212 }
213 }
214
215 StopTimer();
216 vsyncClient_ = nullptr;
217 rendererLooper_ = nullptr;
218 threadHandler_ = nullptr;
219 }
220
OnVsync(uint64_t timestamp)221 void RSRenderThread::OnVsync(uint64_t timestamp)
222 {
223 ROSEN_TRACE_BEGIN(BYTRACE_TAG_GRAPHIC_AGP, "RSRenderThread::OnVsync");
224 mValue = (mValue + 1) % 2; // 1 and 2 is Calculated parameters
225 RS_TRACE_INT("Vsync-client", mValue);
226 timestamp_ = timestamp;
227 if (activeWindowCnt_.load() > 0) {
228 StartTimer(0); // start render-loop now
229 }
230 ROSEN_TRACE_END(BYTRACE_TAG_GRAPHIC_AGP);
231 }
232
UpdateWindowStatus(bool active)233 void RSRenderThread::UpdateWindowStatus(bool active)
234 {
235 if (active) {
236 activeWindowCnt_++;
237 } else {
238 activeWindowCnt_--;
239 }
240 ROSEN_LOGD("RSRenderThread UpdateWindowStatus %d, cur activeWindowCnt_ %d", active, activeWindowCnt_.load());
241 }
242
StartTimer(uint64_t interval)243 void RSRenderThread::StartTimer(uint64_t interval)
244 {
245 if (threadHandler_ != nullptr) {
246 if (timeHandle_ == nullptr) {
247 timeHandle_ = RSThreadHandler::StaticCreateTask(mainFunc_);
248 }
249 threadHandler_->PostTaskDelay(timeHandle_, interval);
250 }
251 }
252
StopTimer()253 void RSRenderThread::StopTimer()
254 {
255 ROSEN_LOGD("RSRenderThread StopTimer.");
256 if (threadHandler_ != nullptr) {
257 if (timeHandle_ != nullptr) {
258 threadHandler_->CancelTask(timeHandle_);
259 }
260 }
261 }
262
ProcessCommands()263 void RSRenderThread::ProcessCommands()
264 {
265 std::unique_lock<std::mutex> cmdLock(cmdMutex_);
266 if (cmds_.empty()) {
267 return;
268 }
269 if (RsFrameReport::GetInstance().GetEnable()) {
270 RsFrameReport::GetInstance().ProcessCommandsStart();
271 }
272
273 ROSEN_LOGD("RSRenderThread ProcessCommands size: %lu\n", cmds_.size());
274 std::vector<std::unique_ptr<RSTransactionData>> cmds;
275 std::swap(cmds, cmds_);
276 cmdLock.unlock();
277
278 ROSEN_TRACE_BEGIN(BYTRACE_TAG_GRAPHIC_AGP, "ProcessCommands");
279 for (auto& cmdData : cmds) {
280 cmdData->Process(context_);
281 }
282 ROSEN_TRACE_END(BYTRACE_TAG_GRAPHIC_AGP);
283 }
284
Animate(uint64_t timestamp)285 void RSRenderThread::Animate(uint64_t timestamp)
286 {
287 RS_TRACE_FUNC();
288
289 if (RsFrameReport::GetInstance().GetEnable()) {
290 RsFrameReport::GetInstance().AnimateStart();
291 }
292
293 if (context_.animatingNodeList_.empty()) {
294 return;
295 }
296
297 // iterate and animate all animating nodes, remove if animation finished
298 std::__libcpp_erase_if_container(context_.animatingNodeList_, [timestamp](const auto& iter) -> bool {
299 auto node = iter.second.lock();
300 if (node == nullptr) {
301 ROSEN_LOGD("RSRenderThread::Animate removing expired animating node");
302 return true;
303 }
304 bool animationFinished = !node->Animate(timestamp);
305 if (animationFinished) {
306 ROSEN_LOGD("RSRenderThread::Animate removing finished animating node %llu", node->GetId());
307 }
308 return animationFinished;
309 });
310
311 RSRenderThread::Instance().RequestNextVSync();
312 }
313
Render()314 void RSRenderThread::Render()
315 {
316 ROSEN_TRACE_BEGIN(BYTRACE_TAG_GRAPHIC_AGP, "RSRenderThread::Render");
317 if (RsFrameReport::GetInstance().GetEnable()) {
318 RsFrameReport::GetInstance().RenderStart();
319 }
320 std::unique_lock<std::mutex> lock(mutex_);
321 const auto& rootNode = context_.GetGlobalRootRenderNode();
322 if (rootNode == nullptr) {
323 ROSEN_LOGE("RSRenderThread::Render, rootNode is nullptr");
324 return;
325 }
326 if (visitor_ == nullptr) {
327 visitor_ = std::make_shared<RSRenderThreadVisitor>();
328 }
329 rootNode->Prepare(visitor_);
330 rootNode->Process(visitor_);
331 ROSEN_TRACE_END(BYTRACE_TAG_GRAPHIC_AGP);
332 }
333
SendCommands()334 void RSRenderThread::SendCommands()
335 {
336 ROSEN_TRACE_BEGIN(BYTRACE_TAG_GRAPHIC_AGP, "RSRenderThread::SendCommands");
337 if (RsFrameReport::GetInstance().GetEnable()) {
338 RsFrameReport::GetInstance().SendCommandsStart();
339 }
340
341 RSUIDirector::RecvMessages();
342 ROSEN_TRACE_END(BYTRACE_TAG_GRAPHIC_AGP);
343 }
344
OnTransaction(std::shared_ptr<RSTransactionData> transactionData)345 void RSRenderThread::OnTransaction(std::shared_ptr<RSTransactionData> transactionData)
346 {
347 ROSEN_TRACE_BEGIN(BYTRACE_TAG_GRAPHIC_AGP, "RSRenderThread::OnTransaction");
348 RSUIDirector::RecvMessages(transactionData);
349 ROSEN_TRACE_END(BYTRACE_TAG_GRAPHIC_AGP);
350 }
351
Detach(NodeId id)352 void RSRenderThread::Detach(NodeId id)
353 {
354 if (auto node = context_.GetNodeMap().GetRenderNode<RSRootRenderNode>(id)) {
355 std::unique_lock<std::mutex> lock(mutex_);
356 context_.GetGlobalRootRenderNode()->RemoveChild(node);
357 }
358 }
359
PostTask(RSTaskMessage::RSTask task)360 void RSRenderThread::PostTask(RSTaskMessage::RSTask task)
361 {
362 if (threadHandler_) {
363 auto taskHandle = threadHandler_->CreateTask(task);
364 threadHandler_->PostTask(taskHandle, 0);
365 }
366 }
367 } // namespace Rosen
368 } // namespace OHOS
369