1 /*
2 * Copyright (c) 2021-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 "pipeline/rs_render_thread.h"
17
18 #include <cstdint>
19
20 #include "rs_trace.h"
21 #include "sandbox_utils.h"
22
23 #include "animation/rs_animation_fraction.h"
24 #include "command/rs_surface_node_command.h"
25 #include "delegate/rs_functional_delegate.h"
26 #include "pipeline/rs_draw_cmd_list.h"
27 #include "pipeline/rs_frame_report.h"
28 #include "pipeline/rs_node_map.h"
29 #include "pipeline/rs_render_node_map.h"
30 #include "pipeline/rs_root_render_node.h"
31 #include "pipeline/rs_surface_render_node.h"
32 #include "platform/common/rs_accessibility.h"
33 #include "platform/common/rs_log.h"
34 #include "platform/common/rs_system_properties.h"
35 #include "property/rs_property_trace.h"
36 #include "transaction/rs_render_service_client.h"
37 #include "ui/rs_surface_extractor.h"
38 #include "ui/rs_surface_node.h"
39 #include "ui/rs_ui_director.h"
40
41 #ifdef OHOS_RSS_CLIENT
42 #include "res_sched_client.h"
43 #include "res_type.h"
44 #endif
45 #ifdef ROSEN_OHOS
46 #include <sys/prctl.h>
47 #include <unistd.h>
48 #include "accessibility_config.h"
49 #include "frame_collector.h"
50 #include "render_frame_trace.h"
51 #include "platform/ohos/overdraw/rs_overdraw_controller.h"
52
53 static const std::string RT_INTERVAL_NAME = "renderthread";
54 #endif
55
SystemCallSetThreadName(const std::string & name)56 static void SystemCallSetThreadName(const std::string& name)
57 {
58 #ifdef ROSEN_OHOS
59 if (prctl(PR_SET_NAME, name.c_str()) < 0) {
60 return;
61 }
62 #endif
63 }
64
65 namespace OHOS {
66 namespace Rosen {
67 namespace {
68 static constexpr uint64_t REFRESH_PERIOD = 16666667;
69 static constexpr uint64_t REFRESH_FREQ_IN_UNI_RENDER = 1200;
70 }
71
SendFrameEvent(bool start)72 void SendFrameEvent(bool start)
73 {
74 #ifdef ROSEN_OHOS
75 FrameCollector::GetInstance().MarkFrameEvent(start ? FrameEventType::WaitVsyncStart : FrameEventType::WaitVsyncEnd);
76 #endif
77 }
78
Instance()79 RSRenderThread& RSRenderThread::Instance()
80 {
81 static RSRenderThread renderThread;
82 RSAnimationFraction::Init();
83 return renderThread;
84 }
85
RSRenderThread()86 RSRenderThread::RSRenderThread()
87 {
88 mainFunc_ = [&]() {
89 uint64_t renderStartTimeStamp;
90 if (needRender_) {
91 renderStartTimeStamp = jankDetector_->GetSysTimeNs();
92 }
93 RS_TRACE_BEGIN("RSRenderThread DrawFrame: " + std::to_string(timestamp_));
94 #ifdef ROSEN_OHOS
95 FRAME_TRACE::RenderFrameTrace::GetInstance().RenderStartFrameTrace(RT_INTERVAL_NAME);
96 #endif
97 prevTimestamp_ = timestamp_;
98 ProcessCommands();
99 ROSEN_LOGD("RSRenderThread DrawFrame(%" PRIu64 ") in %s", prevTimestamp_, renderContext_ ? "GPU" : "CPU");
100 Animate(prevTimestamp_);
101 Render();
102 SendCommands();
103 #ifdef ROSEN_OHOS
104 FRAME_TRACE::RenderFrameTrace::GetInstance().RenderEndFrameTrace(RT_INTERVAL_NAME);
105 #endif
106 if (needRender_) {
107 jankDetector_->CalculateSkippedFrame(renderStartTimeStamp, jankDetector_->GetSysTimeNs());
108 }
109 RS_TRACE_END();
110 };
111
112 context_ = std::make_shared<RSContext>();
113 jankDetector_ = std::make_shared<RSJankDetector>();
114 RSAccessibility::GetInstance().ListenHighContrastChange([](bool newHighContrast) {
115 auto& renderThread = RSRenderThread::Instance();
116 renderThread.SetHighContrast(newHighContrast);
117 });
118 }
119
~RSRenderThread()120 RSRenderThread::~RSRenderThread()
121 {
122 Stop();
123
124 if (renderContext_ != nullptr) {
125 ROSEN_LOGD("Destroy renderContext!!");
126 #if !defined(_WIN32) && !defined(__APPLE__) && !defined(__gnu_linux__)
127 delete renderContext_;
128 renderContext_ = nullptr;
129 #endif
130 }
131 }
132
Start()133 void RSRenderThread::Start()
134 {
135 ROSEN_LOGD("RSRenderThread start.");
136 running_.store(true);
137 if (thread_ == nullptr) {
138 thread_ = std::make_unique<std::thread>(&RSRenderThread::RenderLoop, this);
139 }
140 }
141
Stop()142 void RSRenderThread::Stop()
143 {
144 running_.store(false);
145
146 if (handler_) {
147 handler_->RemoveAllEvents();
148 handler_ = nullptr;
149 }
150 receiver_ = nullptr;
151 if (runner_) {
152 runner_->Stop();
153 }
154
155 if (thread_ != nullptr && thread_->joinable()) {
156 thread_->join();
157 }
158
159 thread_ = nullptr;
160 ROSEN_LOGD("RSRenderThread stopped.");
161 }
162
RecvTransactionData(std::unique_ptr<RSTransactionData> & transactionData)163 void RSRenderThread::RecvTransactionData(std::unique_ptr<RSTransactionData>& transactionData)
164 {
165 {
166 std::unique_lock<std::mutex> cmdLock(cmdMutex_);
167 std::string str = "RecvCommands ptr:" + std::to_string(reinterpret_cast<uintptr_t>(transactionData.get()));
168 commandTimestamp_ = transactionData->GetTimestamp();
169 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, str.c_str());
170 cmds_.emplace_back(std::move(transactionData));
171 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
172 }
173 // [PLANNING]: process in next vsync (temporarily)
174 RSRenderThread::Instance().RequestNextVSync();
175 }
176
RequestNextVSync()177 void RSRenderThread::RequestNextVSync()
178 {
179 if (handler_) {
180 RS_TRACE_FUNC();
181 SendFrameEvent(true);
182 VSyncReceiver::FrameCallback fcb = {
183 .userData_ = this,
184 .callback_ = std::bind(&RSRenderThread::OnVsync, this, std::placeholders::_1),
185 };
186 if (receiver_ != nullptr) {
187 receiver_->RequestNextVSync(fcb);
188 } else {
189 hasSkipVsync_ = true;
190 }
191 } else {
192 hasSkipVsync_ = true;
193 }
194 }
195
GetTid()196 int32_t RSRenderThread::GetTid()
197 {
198 return tid_;
199 }
200
CreateAndInitRenderContextIfNeed()201 void RSRenderThread::CreateAndInitRenderContextIfNeed()
202 {
203 #ifdef ACE_ENABLE_GL
204 if (needRender_ && renderContext_ == nullptr) {
205 #if !defined(_WIN32) && !defined(__APPLE__) && !defined(__gnu_linux__)
206 renderContext_ = new RenderContext();
207 #endif
208 ROSEN_LOGD("Create RenderContext, its pointer is %p", renderContext_);
209 RS_TRACE_NAME("InitializeEglContext");
210 #if !defined(_WIN32) && !defined(__APPLE__) && !defined(__gnu_linux__)
211 renderContext_->InitializeEglContext(); // init egl context on RT
212 if (!cacheDir_.empty()) {
213 renderContext_->SetCacheDir(cacheDir_);
214 }
215 #endif
216 }
217 #endif
218 }
219
RenderLoop()220 void RSRenderThread::RenderLoop()
221 {
222 SystemCallSetThreadName("RSRenderThread");
223
224 #ifdef OHOS_RSS_CLIENT
225 std::unordered_map<std::string, std::string> payload;
226 payload["uid"] = std::to_string(getuid());
227 payload["pid"] = std::to_string(GetRealPid());
228 ResourceSchedule::ResSchedClient::GetInstance().ReportData(
229 ResourceSchedule::ResType::RES_TYPE_REPORT_RENDER_THREAD, gettid(), payload);
230 #endif
231 #ifdef ROSEN_OHOS
232 tid_ = gettid();
233 #endif
234 if (RSSystemProperties::GetUniRenderEnabled()) {
235 needRender_ = std::static_pointer_cast<RSRenderServiceClient>(RSIRenderClient::CreateRenderServiceClient())
236 ->QueryIfRTNeedRender();
237 RSSystemProperties::SetRenderMode(!needRender_);
238 DrawCmdListManager::Instance().MarkForceClear(!needRender_);
239 }
240 CreateAndInitRenderContextIfNeed();
241 std::string name = "RSRenderThread_" + std::to_string(GetRealPid());
242 runner_ = AppExecFwk::EventRunner::Create(false);
243 handler_ = std::make_shared<AppExecFwk::EventHandler>(runner_);
244 auto rsClient = std::static_pointer_cast<RSRenderServiceClient>(RSIRenderClient::CreateRenderServiceClient());
245 receiver_ = rsClient->CreateVSyncReceiver(name, handler_);
246 if (receiver_ == nullptr) {
247 ROSEN_LOGE("RSRenderThread CreateVSyncReceiver Error");
248 return;
249 }
250 receiver_->Init();
251 if (hasSkipVsync_) {
252 hasSkipVsync_ = false;
253 RSRenderThread::Instance().RequestNextVSync();
254 }
255
256 #ifdef ROSEN_OHOS
257 FrameCollector::GetInstance().SetRepaintCallback([this]() { this->RequestNextVSync(); });
258
259 auto delegate = RSFunctionalDelegate::Create();
260 delegate->SetRepaintCallback([this]() { this->RequestNextVSync(); });
261 RSOverdrawController::GetInstance().SetDelegate(delegate);
262 #endif
263
264 if (runner_) {
265 runner_->Run();
266 }
267 }
268
OnVsync(uint64_t timestamp)269 void RSRenderThread::OnVsync(uint64_t timestamp)
270 {
271 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "RSRenderThread::OnVsync");
272 SendFrameEvent(false);
273 mValue = (mValue + 1) % 2; // 1 and 2 is Calculated parameters
274 RS_TRACE_INT("Vsync-client", mValue);
275 timestamp_ = timestamp;
276 if (activeWindowCnt_.load() > 0 &&
277 (needRender_ || (timestamp_ - prevTimestamp_) / REFRESH_PERIOD >= REFRESH_FREQ_IN_UNI_RENDER)) {
278 mainFunc_(); // start render-loop now
279 }
280 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
281 }
282
UpdateWindowStatus(bool active)283 void RSRenderThread::UpdateWindowStatus(bool active)
284 {
285 if (active) {
286 activeWindowCnt_++;
287 } else {
288 activeWindowCnt_--;
289 }
290 ROSEN_LOGD("RSRenderThread UpdateWindowStatus %d, cur activeWindowCnt_ %d", active, activeWindowCnt_.load());
291 }
292
UpdateRenderMode(bool needRender)293 void RSRenderThread::UpdateRenderMode(bool needRender)
294 {
295 if (handler_) {
296 handler_->PostTask([needRender = needRender, this]() {
297 RequestNextVSync();
298 if (!needRender) { // change to uni render, should move surfaceView's position
299 UpdateSurfaceNodeParentInRS();
300 } else {
301 needRender_ = needRender;
302 MarkNeedUpdateSurfaceNode();
303 CreateAndInitRenderContextIfNeed();
304 DrawCmdListManager::Instance().MarkForceClear(!needRender_);
305 }
306 }, AppExecFwk::EventQueue::Priority::IMMEDIATE);
307 }
308 }
309
NotifyClearBufferCache()310 void RSRenderThread::NotifyClearBufferCache()
311 {
312 if (handler_) {
313 handler_->PostTask([this]() {
314 needRender_ = false;
315 ClearBufferCache();
316 DrawCmdListManager::Instance().MarkForceClear(!needRender_);
317 }, AppExecFwk::EventQueue::Priority::IMMEDIATE);
318 }
319 }
320
UpdateSurfaceNodeParentInRS()321 void RSRenderThread::UpdateSurfaceNodeParentInRS()
322 {
323 auto& nodeMap = context_->GetMutableNodeMap();
324 std::unordered_map<NodeId, NodeId> surfaceNodeMap; // [surfaceNodeId, parentId]
325 nodeMap.TraverseSurfaceNodes([&surfaceNodeMap](const std::shared_ptr<RSSurfaceRenderNode>& node) mutable {
326 if (!node) {
327 return;
328 }
329 auto parent = node->GetParent().lock();
330 if (!parent) {
331 return;
332 }
333 surfaceNodeMap.emplace(node->GetId(), parent->GetId());
334 });
335 auto transactionProxy = RSTransactionProxy::GetInstance();
336 if (transactionProxy != nullptr) {
337 for (auto& [surfaceNodeId, parentId] : surfaceNodeMap) {
338 std::unique_ptr<RSCommand> command =
339 std::make_unique<RSSurfaceNodeUpdateParentWithoutTransition>(surfaceNodeId, parentId);
340 transactionProxy->AddCommandFromRT(command, surfaceNodeId, FollowType::FOLLOW_TO_SELF);
341 }
342 transactionProxy->FlushImplicitTransactionFromRT(uiTimestamp_);
343 }
344 }
345
ClearBufferCache()346 void RSRenderThread::ClearBufferCache()
347 {
348 const auto& rootNode = context_->GetGlobalRootRenderNode();
349 if (rootNode == nullptr) {
350 ROSEN_LOGE("RSRenderThread::ClearBufferCache, rootNode is nullptr");
351 return;
352 }
353 for (auto& child : rootNode->GetSortedChildren()) {
354 if (!child || !child->IsInstanceOf<RSRootRenderNode>()) {
355 continue;
356 }
357 auto childNode = child->ReinterpretCastTo<RSRootRenderNode>();
358 auto surfaceNode = RSNodeMap::Instance().GetNode<RSSurfaceNode>(childNode->GetRSSurfaceNodeId());
359 auto rsSurface = RSSurfaceExtractor::ExtractRSSurface(surfaceNode);
360 if (rsSurface != nullptr) {
361 rsSurface->ClearAllBuffer();
362 }
363 }
364 rootNode->ResetSortedChildren();
365 }
366
367
MarkNeedUpdateSurfaceNode()368 void RSRenderThread::MarkNeedUpdateSurfaceNode()
369 {
370 const auto& rootNode = context_->GetGlobalRootRenderNode();
371 if (rootNode == nullptr) {
372 ROSEN_LOGE("RSRenderThread::MarkNeedUpdateSurfaceNode, rootNode is nullptr");
373 return;
374 }
375 for (auto& child : rootNode->GetSortedChildren()) {
376 if (!child || !child->IsInstanceOf<RSRootRenderNode>()) {
377 continue;
378 }
379 auto childNode = child->ReinterpretCastTo<RSRootRenderNode>();
380 childNode->SetNeedUpdateSurfaceNode(true);
381 }
382 rootNode->ResetSortedChildren();
383 }
384
ProcessCommands()385 void RSRenderThread::ProcessCommands()
386 {
387 // Attention: there are two situations
388 // 1. when commandTimestamp_ != 0, it means that UIDirector has called
389 // "RSRenderThread::Instance().RequestNextVSync()", which equals there are some commands form UIThread need to be
390 // executed. To make commands from UIThread sync with buffer flushed by RenderThread, we choose commandTimestamp_ as
391 // uiTimestamp_ which would be used in RenderThreadVisitor when we call flushFrame.
392 // 2. when cmds_.empty() is true or commandTimestamp_ = 0,
393 // it means that some thread except UIThread like RSRenderThread::Animate
394 // has called "RSRenderThread::Instance().RequestNextVSync()", which equals that some commands form RenderThread
395 // need to be executed. To make commands from RenderThread sync with buffer flushed by RenderThread, we choose
396 // (prevTimestamp_ - 1) as uiTimestamp_ which would be used in RenderThreadVisitor when we call flushFrame.
397
398 // The reason why prevTimestamp_ need to be minus 1 is that timestamp used in UIThread is always less than (for now)
399 // timestamp used in RenderThread. If we do not do this, when RenderThread::Animate execute flushFrame and use
400 // prevTimestamp_ as buffer timestamp which equals T0, UIDirector send messages in the same vsync period, and the
401 // commandTimestamp_ would also be T0, RenderService would execute commands from UIDirector and composite buffer
402 // which rendering is executed by RSRenderThread::Animate for they have the same timestamp. To avoid this situation,
403 // we should always use "prevTimestamp_ - 1".
404
405 std::unique_lock<std::mutex> cmdLock(cmdMutex_);
406 if (cmds_.empty()) {
407 uiTimestamp_ = prevTimestamp_ - 1;
408 return;
409 }
410 if (RsFrameReport::GetInstance().GetEnable() && needRender_) {
411 RsFrameReport::GetInstance().ProcessCommandsStart();
412 }
413
414 if (commandTimestamp_ != 0) {
415 uiTimestamp_ = commandTimestamp_;
416 commandTimestamp_ = 0;
417 } else {
418 uiTimestamp_ = prevTimestamp_ - 1;
419 }
420
421 ROSEN_LOGD("RSRenderThread ProcessCommands size: %lu\n", cmds_.size());
422 std::vector<std::unique_ptr<RSTransactionData>> cmds;
423 std::swap(cmds, cmds_);
424 cmdLock.unlock();
425
426 // To improve overall responsiveness, we make animations start on LAST frame instead of THIS frame.
427 // If last frame is too far away (earlier than 2 vsync from now), we use currentTimestamp_ - REFRESH_PERIOD as
428 // 'virtual' last frame timestamp.
429 if (timestamp_ - lastAnimateTimestamp_ > 2 * REFRESH_PERIOD) { // 2: if last frame is earlier than 2 vsync from now
430 context_->currentTimestamp_ = timestamp_ - REFRESH_PERIOD;
431 } else {
432 context_->currentTimestamp_ = lastAnimateTimestamp_;
433 }
434 uint64_t uiEndTimeStamp = 0;
435 if (needRender_) {
436 uiEndTimeStamp = jankDetector_->GetSysTimeNs();
437 }
438 for (auto& cmdData : cmds) {
439 std::string str = "ProcessCommands ptr:" + std::to_string(reinterpret_cast<uintptr_t>(cmdData.get()));
440 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, str.c_str());
441 // only set transactionTimestamp_ in UniRender mode
442 context_->transactionTimestamp_ = RSSystemProperties::GetUniRenderEnabled() ? cmdData->GetTimestamp() : 0;
443 cmdData->Process(*context_);
444 if (needRender_) {
445 jankDetector_->UpdateUiDrawFrameMsg(cmdData->GetTimestamp(), uiEndTimeStamp, cmdData->GetAbilityName());
446 }
447 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
448 }
449 }
450
Animate(uint64_t timestamp)451 void RSRenderThread::Animate(uint64_t timestamp)
452 {
453 RS_TRACE_FUNC();
454
455 if (RsFrameReport::GetInstance().GetEnable() && needRender_) {
456 RsFrameReport::GetInstance().AnimateStart();
457 }
458
459 lastAnimateTimestamp_ = timestamp;
460
461 if (context_->animatingNodeList_.empty()) {
462 return;
463 }
464
465 bool needRequestNextVsync = false;
466 // iterate and animate all animating nodes, remove if animation finished
467 EraseIf(context_->animatingNodeList_,
468 [timestamp, &needRequestNextVsync](const auto& iter) -> bool {
469 auto node = iter.second.lock();
470 if (node == nullptr) {
471 ROSEN_LOGD("RSRenderThread::Animate removing expired animating node");
472 return true;
473 }
474 auto result = node->Animate(timestamp);
475 if (!result.first) {
476 ROSEN_LOGD("RSRenderThread::Animate removing finished animating node %" PRIu64, node->GetId());
477 }
478 needRequestNextVsync = needRequestNextVsync || result.second;
479 return !result.first;
480 });
481
482 if (needRequestNextVsync) {
483 RSRenderThread::Instance().RequestNextVSync();
484 }
485 }
486
Render()487 void RSRenderThread::Render()
488 {
489 if (!needRender_) {
490 return;
491 }
492 if (RSSystemProperties::GetRenderNodeTraceEnabled()) {
493 RSPropertyTrace::GetInstance().RefreshNodeTraceInfo();
494 }
495 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "RSRenderThread::Render");
496 if (RsFrameReport::GetInstance().GetEnable()) {
497 RsFrameReport::GetInstance().RenderStart();
498 }
499 std::unique_lock<std::mutex> lock(mutex_);
500 const auto& rootNode = context_->GetGlobalRootRenderNode();
501
502 if (rootNode == nullptr) {
503 ROSEN_LOGE("RSRenderThread::Render, rootNode is nullptr");
504 return;
505 }
506 if (visitor_ == nullptr) {
507 visitor_ = std::make_shared<RSRenderThreadVisitor>();
508 }
509 // get latest partial render status from system properties and set it to RTvisitor_
510 visitor_->SetPartialRenderStatus(RSSystemProperties::GetPartialRenderEnabled(), isRTRenderForced_);
511 rootNode->Prepare(visitor_);
512 rootNode->Process(visitor_);
513 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
514 }
515
SendCommands()516 void RSRenderThread::SendCommands()
517 {
518 ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "RSRenderThread::SendCommands");
519 if (RsFrameReport::GetInstance().GetEnable() && needRender_) {
520 RsFrameReport::GetInstance().SendCommandsStart();
521 }
522
523 RSUIDirector::RecvMessages(needRender_);
524 ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
525 }
526
Detach(NodeId id)527 void RSRenderThread::Detach(NodeId id)
528 {
529 if (auto node = context_->GetNodeMap().GetRenderNode<RSRootRenderNode>(id)) {
530 std::unique_lock<std::mutex> lock(mutex_);
531 context_->GetGlobalRootRenderNode()->RemoveChild(node);
532 }
533 }
534
PostTask(RSTaskMessage::RSTask task)535 void RSRenderThread::PostTask(RSTaskMessage::RSTask task)
536 {
537 if (handler_) {
538 handler_->PostTask(task);
539 }
540 }
541
PostPreTask()542 void RSRenderThread::PostPreTask()
543 {
544 if (handler_ && preTask_) {
545 handler_->PostTask(preTask_);
546 }
547 }
548 } // namespace Rosen
549 } // namespace OHOS
550